{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: torch==2.2 in /opt/conda/lib/python3.10/site-packages (2.2.0)\n",
      "Requirement already satisfied: filelock in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (3.13.1)\n",
      "Requirement already satisfied: typing-extensions>=4.8.0 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (4.9.0)\n",
      "Requirement already satisfied: sympy in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (1.12)\n",
      "Requirement already satisfied: networkx in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (2.8.5)\n",
      "Requirement already satisfied: jinja2 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (3.1.2)\n",
      "Requirement already satisfied: fsspec in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (2023.12.2)\n",
      "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cudnn-cu12==8.9.2.26 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (8.9.2.26)\n",
      "Requirement already satisfied: nvidia-cublas-cu12==12.1.3.1 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.3.1)\n",
      "Requirement already satisfied: nvidia-cufft-cu12==11.0.2.54 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (11.0.2.54)\n",
      "Requirement already satisfied: nvidia-curand-cu12==10.3.2.106 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (10.3.2.106)\n",
      "Requirement already satisfied: nvidia-cusolver-cu12==11.4.5.107 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (11.4.5.107)\n",
      "Requirement already satisfied: nvidia-cusparse-cu12==12.1.0.106 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.0.106)\n",
      "Requirement already satisfied: nvidia-nccl-cu12==2.19.3 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (2.19.3)\n",
      "Requirement already satisfied: nvidia-nvtx-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.105)\n",
      "Requirement already satisfied: triton==2.2.0 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (2.2.0)\n",
      "Requirement already satisfied: nvidia-nvjitlink-cu12 in /opt/conda/lib/python3.10/site-packages (from nvidia-cusolver-cu12==11.4.5.107->torch==2.2) (12.3.101)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.10/site-packages (from jinja2->torch==2.2) (2.1.3)\n",
      "Requirement already satisfied: mpmath>=0.19 in /opt/conda/lib/python3.10/site-packages (from sympy->torch==2.2) (1.3.0)\n",
      "Requirement already satisfied: torchvision==0.17.0 in /opt/conda/lib/python3.10/site-packages (0.17.0)\n",
      "Requirement already satisfied: numpy in /opt/conda/lib/python3.10/site-packages (from torchvision==0.17.0) (1.26.2)\n",
      "Requirement already satisfied: requests in /opt/conda/lib/python3.10/site-packages (from torchvision==0.17.0) (2.28.1)\n",
      "Requirement already satisfied: torch==2.2.0 in /opt/conda/lib/python3.10/site-packages (from torchvision==0.17.0) (2.2.0)\n",
      "Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in /opt/conda/lib/python3.10/site-packages (from torchvision==0.17.0) (9.3.0)\n",
      "Requirement already satisfied: filelock in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (3.13.1)\n",
      "Requirement already satisfied: typing-extensions>=4.8.0 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (4.9.0)\n",
      "Requirement already satisfied: sympy in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (1.12)\n",
      "Requirement already satisfied: networkx in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (2.8.5)\n",
      "Requirement already satisfied: jinja2 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (3.1.2)\n",
      "Requirement already satisfied: fsspec in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (2023.12.2)\n",
      "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cudnn-cu12==8.9.2.26 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (8.9.2.26)\n",
      "Requirement already satisfied: nvidia-cublas-cu12==12.1.3.1 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (12.1.3.1)\n",
      "Requirement already satisfied: nvidia-cufft-cu12==11.0.2.54 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (11.0.2.54)\n",
      "Requirement already satisfied: nvidia-curand-cu12==10.3.2.106 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (10.3.2.106)\n",
      "Requirement already satisfied: nvidia-cusolver-cu12==11.4.5.107 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (11.4.5.107)\n",
      "Requirement already satisfied: nvidia-cusparse-cu12==12.1.0.106 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (12.1.0.106)\n",
      "Requirement already satisfied: nvidia-nccl-cu12==2.19.3 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (2.19.3)\n",
      "Requirement already satisfied: nvidia-nvtx-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (12.1.105)\n",
      "Requirement already satisfied: triton==2.2.0 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17.0) (2.2.0)\n",
      "Requirement already satisfied: nvidia-nvjitlink-cu12 in /opt/conda/lib/python3.10/site-packages (from nvidia-cusolver-cu12==11.4.5.107->torch==2.2.0->torchvision==0.17.0) (12.3.101)\n",
      "Requirement already satisfied: charset-normalizer<3,>=2 in /opt/conda/lib/python3.10/site-packages (from requests->torchvision==0.17.0) (2.1.0)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.10/site-packages (from requests->torchvision==0.17.0) (3.3)\n",
      "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /opt/conda/lib/python3.10/site-packages (from requests->torchvision==0.17.0) (1.26.10)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.10/site-packages (from requests->torchvision==0.17.0) (2022.6.15)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.10/site-packages (from jinja2->torch==2.2.0->torchvision==0.17.0) (2.1.3)\n",
      "Requirement already satisfied: mpmath>=0.19 in /opt/conda/lib/python3.10/site-packages (from sympy->torch==2.2.0->torchvision==0.17.0) (1.3.0)\n",
      "Requirement already satisfied: matplotlib==3.5.2 in /opt/conda/lib/python3.10/site-packages (3.5.2)\n",
      "Requirement already satisfied: cycler>=0.10 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (0.12.1)\n",
      "Requirement already satisfied: fonttools>=4.22.0 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (4.46.0)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (1.4.5)\n",
      "Requirement already satisfied: numpy>=1.17 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (1.26.2)\n",
      "Requirement already satisfied: packaging>=20.0 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (21.3)\n",
      "Requirement already satisfied: pillow>=6.2.0 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (9.3.0)\n",
      "Requirement already satisfied: pyparsing>=2.2.1 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (3.0.9)\n",
      "Requirement already satisfied: python-dateutil>=2.7 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (2.8.2)\n",
      "Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib==3.5.2) (1.16.0)\n",
      "Requirement already satisfied: scikit-image==0.19.3 in /opt/conda/lib/python3.10/site-packages (0.19.3)\n",
      "Requirement already satisfied: numpy>=1.17.0 in /opt/conda/lib/python3.10/site-packages (from scikit-image==0.19.3) (1.26.2)\n",
      "Requirement already satisfied: scipy>=1.4.1 in /opt/conda/lib/python3.10/site-packages (from scikit-image==0.19.3) (1.11.4)\n",
      "Requirement already satisfied: networkx>=2.2 in /opt/conda/lib/python3.10/site-packages (from scikit-image==0.19.3) (2.8.5)\n",
      "Requirement already satisfied: pillow!=7.1.0,!=7.1.1,!=8.3.0,>=6.1.0 in /opt/conda/lib/python3.10/site-packages (from scikit-image==0.19.3) (9.3.0)\n",
      "Requirement already satisfied: imageio>=2.4.1 in /opt/conda/lib/python3.10/site-packages (from scikit-image==0.19.3) (2.33.0)\n",
      "Requirement already satisfied: tifffile>=2019.7.26 in /opt/conda/lib/python3.10/site-packages (from scikit-image==0.19.3) (2023.12.9)\n",
      "Requirement already satisfied: PyWavelets>=1.1.1 in /opt/conda/lib/python3.10/site-packages (from scikit-image==0.19.3) (1.5.0)\n",
      "Requirement already satisfied: packaging>=20.0 in /opt/conda/lib/python3.10/site-packages (from scikit-image==0.19.3) (21.3)\n",
      "Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /opt/conda/lib/python3.10/site-packages (from packaging>=20.0->scikit-image==0.19.3) (3.0.9)\n",
      "Collecting captum==0.5.0\n",
      "  Downloading captum-0.5.0-py3-none-any.whl (1.4 MB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.4/1.4 MB\u001b[0m \u001b[31m35.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: matplotlib in /opt/conda/lib/python3.10/site-packages (from captum==0.5.0) (3.5.2)\n",
      "Requirement already satisfied: numpy in /opt/conda/lib/python3.10/site-packages (from captum==0.5.0) (1.26.2)\n",
      "Requirement already satisfied: torch>=1.6 in /opt/conda/lib/python3.10/site-packages (from captum==0.5.0) (2.2.0)\n",
      "Requirement already satisfied: filelock in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (3.13.1)\n",
      "Requirement already satisfied: typing-extensions>=4.8.0 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (4.9.0)\n",
      "Requirement already satisfied: sympy in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (1.12)\n",
      "Requirement already satisfied: networkx in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (2.8.5)\n",
      "Requirement already satisfied: jinja2 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (3.1.2)\n",
      "Requirement already satisfied: fsspec in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (2023.12.2)\n",
      "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cudnn-cu12==8.9.2.26 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (8.9.2.26)\n",
      "Requirement already satisfied: nvidia-cublas-cu12==12.1.3.1 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (12.1.3.1)\n",
      "Requirement already satisfied: nvidia-cufft-cu12==11.0.2.54 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (11.0.2.54)\n",
      "Requirement already satisfied: nvidia-curand-cu12==10.3.2.106 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (10.3.2.106)\n",
      "Requirement already satisfied: nvidia-cusolver-cu12==11.4.5.107 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (11.4.5.107)\n",
      "Requirement already satisfied: nvidia-cusparse-cu12==12.1.0.106 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (12.1.0.106)\n",
      "Requirement already satisfied: nvidia-nccl-cu12==2.19.3 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (2.19.3)\n",
      "Requirement already satisfied: nvidia-nvtx-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (12.1.105)\n",
      "Requirement already satisfied: triton==2.2.0 in /opt/conda/lib/python3.10/site-packages (from torch>=1.6->captum==0.5.0) (2.2.0)\n",
      "Requirement already satisfied: nvidia-nvjitlink-cu12 in /opt/conda/lib/python3.10/site-packages (from nvidia-cusolver-cu12==11.4.5.107->torch>=1.6->captum==0.5.0) (12.3.101)\n",
      "Requirement already satisfied: cycler>=0.10 in /opt/conda/lib/python3.10/site-packages (from matplotlib->captum==0.5.0) (0.12.1)\n",
      "Requirement already satisfied: fonttools>=4.22.0 in /opt/conda/lib/python3.10/site-packages (from matplotlib->captum==0.5.0) (4.46.0)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /opt/conda/lib/python3.10/site-packages (from matplotlib->captum==0.5.0) (1.4.5)\n",
      "Requirement already satisfied: packaging>=20.0 in /opt/conda/lib/python3.10/site-packages (from matplotlib->captum==0.5.0) (21.3)\n",
      "Requirement already satisfied: pillow>=6.2.0 in /opt/conda/lib/python3.10/site-packages (from matplotlib->captum==0.5.0) (9.3.0)\n",
      "Requirement already satisfied: pyparsing>=2.2.1 in /opt/conda/lib/python3.10/site-packages (from matplotlib->captum==0.5.0) (3.0.9)\n",
      "Requirement already satisfied: python-dateutil>=2.7 in /opt/conda/lib/python3.10/site-packages (from matplotlib->captum==0.5.0) (2.8.2)\n",
      "Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib->captum==0.5.0) (1.16.0)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.10/site-packages (from jinja2->torch>=1.6->captum==0.5.0) (2.1.3)\n",
      "Requirement already satisfied: mpmath>=0.19 in /opt/conda/lib/python3.10/site-packages (from sympy->torch>=1.6->captum==0.5.0) (1.3.0)\n",
      "Installing collected packages: captum\n",
      "Successfully installed captum-0.5.0\n"
     ]
    }
   ],
   "source": [
    "!pip install torch==2.2\n",
    "!pip install torchvision==0.17.0\n",
    "!pip install matplotlib==3.5.2\n",
    "!pip install scikit-image==0.19.3\n",
    "!pip install captum==0.5.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## import modules"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/conda/lib/python3.10/site-packages/transformers/utils/generic.py:441: UserWarning: torch.utils._pytree._register_pytree_node is deprecated. Please use torch.utils._pytree.register_pytree_node instead.\n",
      "  _torch_pytree._register_pytree_node(\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "from torch.utils.data import DataLoader\n",
    "from torchvision import datasets, transforms\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "from captum.attr import IntegratedGradients\n",
    "from captum.attr import Saliency\n",
    "from captum.attr import DeepLift\n",
    "from captum.attr import visualization as viz"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(123)\n",
    "torch.use_deterministic_algorithms(True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## define model architecture"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "class ConvNet(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(ConvNet, self).__init__()\n",
    "        self.cn1 = nn.Conv2d(1, 16, 3, 1)\n",
    "        self.cn2 = nn.Conv2d(16, 32, 3, 1)\n",
    "        self.dp1 = nn.Dropout2d(0.10)\n",
    "        self.dp2 = nn.Dropout2d(0.25)\n",
    "        self.fc1 = nn.Linear(4608, 64) # 4608 is basically 12 X 12 X 32\n",
    "        self.fc2 = nn.Linear(64, 10)\n",
    " \n",
    "    def forward(self, x):\n",
    "        x = self.cn1(x)\n",
    "        x = F.relu(x)\n",
    "        x = self.cn2(x)\n",
    "        x = F.relu(x)\n",
    "        x = F.max_pool2d(x, 2)\n",
    "        x = self.dp1(x)\n",
    "        x = torch.flatten(x, 1)\n",
    "        x = self.fc1(x)\n",
    "        x = F.relu(x)\n",
    "        x = self.dp2(x)\n",
    "        x = self.fc2(x)\n",
    "        op = F.log_softmax(x, dim=1)\n",
    "        return op"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## define training and inference routines"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train(model, device, train_dataloader, optim, epoch):\n",
    "    model.train()\n",
    "    for b_i, (X, y) in enumerate(train_dataloader):\n",
    "        X, y = X.to(device), y.to(device)\n",
    "        optim.zero_grad()\n",
    "        pred_prob = model(X)\n",
    "        loss = F.nll_loss(pred_prob, y) # nll is the negative likelihood loss\n",
    "        loss.backward()\n",
    "        optim.step()\n",
    "        if b_i % 10 == 0:\n",
    "            print('epoch: {} [{}/{} ({:.0f}%)]\\t training loss: {:.6f}'.format(\n",
    "                epoch, b_i * len(X), len(train_dataloader.dataset),\n",
    "                100. * b_i / len(train_dataloader), loss.item()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def test(model, device, test_dataloader):\n",
    "    model.eval()\n",
    "    loss = 0\n",
    "    success = 0\n",
    "    with torch.no_grad():\n",
    "        for X, y in test_dataloader:\n",
    "            X, y = X.to(device), y.to(device)\n",
    "            pred_prob = model(X)\n",
    "            loss += F.nll_loss(pred_prob, y, reduction='sum').item()  # loss summed across the batch\n",
    "            pred = pred_prob.argmax(dim=1, keepdim=True)  # us argmax to get the most likely prediction\n",
    "            success += pred.eq(y.view_as(pred)).sum().item()\n",
    "\n",
    "    loss /= len(test_dataloader.dataset)\n",
    "\n",
    "    print('\\nTest dataset: Overall Loss: {:.4f}, Overall Accuracy: {}/{} ({:.0f}%)\\n'.format(\n",
    "        loss, success, len(test_dataloader.dataset),\n",
    "        100. * success / len(test_dataloader.dataset)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## create data loaders"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# The mean and standard deviation values are calculated as the mean of all pixel values of all images in the training dataset\n",
    "train_dataloader = torch.utils.data.DataLoader(\n",
    "    datasets.MNIST('../data', train=True, download=True,\n",
    "                   transform=transforms.Compose([\n",
    "                       transforms.ToTensor(),\n",
    "                       transforms.Normalize((0.1302,), (0.3069,))])), # train_X.mean()/256. and train_X.std()/256.\n",
    "    batch_size=32, shuffle=True)\n",
    "\n",
    "test_dataloader = torch.utils.data.DataLoader(\n",
    "    datasets.MNIST('../data', train=False, \n",
    "                   transform=transforms.Compose([\n",
    "                       transforms.ToTensor(),\n",
    "                       transforms.Normalize((0.1302,), (0.3069,)) \n",
    "                   ])),\n",
    "    batch_size=500, shuffle=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## define optimizer and run training epochs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "torch.manual_seed(0)\n",
    "device = torch.device(\"cpu\")\n",
    "\n",
    "model = ConvNet()\n",
    "optimizer = optim.Adadelta(model.parameters(), lr=0.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## model training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/conda/lib/python3.10/site-packages/torch/nn/functional.py:1347: UserWarning: dropout2d: Received a 2-D input to dropout2d, which is deprecated and will result in an error in a future release. To retain the behavior and silence this warning, please use dropout instead. Note that dropout2d exists to provide channel-wise dropout on inputs with 2 spatial dimensions, a channel dimension, and an optional batch dimension (i.e. 3D or 4D inputs).\n",
      "  warnings.warn(warn_msg)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 1 [0/60000 (0%)]\t training loss: 2.310609\n",
      "epoch: 1 [320/60000 (1%)]\t training loss: 1.924133\n",
      "epoch: 1 [640/60000 (1%)]\t training loss: 1.313337\n",
      "epoch: 1 [960/60000 (2%)]\t training loss: 0.796470\n",
      "epoch: 1 [1280/60000 (2%)]\t training loss: 0.819801\n",
      "epoch: 1 [1600/60000 (3%)]\t training loss: 0.678459\n",
      "epoch: 1 [1920/60000 (3%)]\t training loss: 0.477066\n",
      "epoch: 1 [2240/60000 (4%)]\t training loss: 0.527125\n",
      "epoch: 1 [2560/60000 (4%)]\t training loss: 0.469366\n",
      "epoch: 1 [2880/60000 (5%)]\t training loss: 0.239070\n",
      "epoch: 1 [3200/60000 (5%)]\t training loss: 0.523908\n",
      "epoch: 1 [3520/60000 (6%)]\t training loss: 0.267831\n",
      "epoch: 1 [3840/60000 (6%)]\t training loss: 0.464627\n",
      "epoch: 1 [4160/60000 (7%)]\t training loss: 0.413977\n",
      "epoch: 1 [4480/60000 (7%)]\t training loss: 0.324858\n",
      "epoch: 1 [4800/60000 (8%)]\t training loss: 0.495965\n",
      "epoch: 1 [5120/60000 (9%)]\t training loss: 0.153463\n",
      "epoch: 1 [5440/60000 (9%)]\t training loss: 0.377620\n",
      "epoch: 1 [5760/60000 (10%)]\t training loss: 0.097269\n",
      "epoch: 1 [6080/60000 (10%)]\t training loss: 0.181864\n",
      "epoch: 1 [6400/60000 (11%)]\t training loss: 0.295800\n",
      "epoch: 1 [6720/60000 (11%)]\t training loss: 0.082916\n",
      "epoch: 1 [7040/60000 (12%)]\t training loss: 0.353389\n",
      "epoch: 1 [7360/60000 (12%)]\t training loss: 0.040657\n",
      "epoch: 1 [7680/60000 (13%)]\t training loss: 0.365705\n",
      "epoch: 1 [8000/60000 (13%)]\t training loss: 0.231380\n",
      "epoch: 1 [8320/60000 (14%)]\t training loss: 0.321043\n",
      "epoch: 1 [8640/60000 (14%)]\t training loss: 0.211378\n",
      "epoch: 1 [8960/60000 (15%)]\t training loss: 0.054053\n",
      "epoch: 1 [9280/60000 (15%)]\t training loss: 0.337620\n",
      "epoch: 1 [9600/60000 (16%)]\t training loss: 0.216428\n",
      "epoch: 1 [9920/60000 (17%)]\t training loss: 0.174468\n",
      "epoch: 1 [10240/60000 (17%)]\t training loss: 0.213010\n",
      "epoch: 1 [10560/60000 (18%)]\t training loss: 0.357055\n",
      "epoch: 1 [10880/60000 (18%)]\t training loss: 0.070653\n",
      "epoch: 1 [11200/60000 (19%)]\t training loss: 0.055425\n",
      "epoch: 1 [11520/60000 (19%)]\t training loss: 0.230391\n",
      "epoch: 1 [11840/60000 (20%)]\t training loss: 0.048202\n",
      "epoch: 1 [12160/60000 (20%)]\t training loss: 0.403469\n",
      "epoch: 1 [12480/60000 (21%)]\t training loss: 0.025848\n",
      "epoch: 1 [12800/60000 (21%)]\t training loss: 0.104852\n",
      "epoch: 1 [13120/60000 (22%)]\t training loss: 0.101376\n",
      "epoch: 1 [13440/60000 (22%)]\t training loss: 0.178021\n",
      "epoch: 1 [13760/60000 (23%)]\t training loss: 0.070927\n",
      "epoch: 1 [14080/60000 (23%)]\t training loss: 0.048668\n",
      "epoch: 1 [14400/60000 (24%)]\t training loss: 0.090581\n",
      "epoch: 1 [14720/60000 (25%)]\t training loss: 0.165846\n",
      "epoch: 1 [15040/60000 (25%)]\t training loss: 0.324705\n",
      "epoch: 1 [15360/60000 (26%)]\t training loss: 0.077008\n",
      "epoch: 1 [15680/60000 (26%)]\t training loss: 0.128724\n",
      "epoch: 1 [16000/60000 (27%)]\t training loss: 0.084200\n",
      "epoch: 1 [16320/60000 (27%)]\t training loss: 0.158558\n",
      "epoch: 1 [16640/60000 (28%)]\t training loss: 0.040566\n",
      "epoch: 1 [16960/60000 (28%)]\t training loss: 0.287925\n",
      "epoch: 1 [17280/60000 (29%)]\t training loss: 0.057604\n",
      "epoch: 1 [17600/60000 (29%)]\t training loss: 0.031712\n",
      "epoch: 1 [17920/60000 (30%)]\t training loss: 0.046777\n",
      "epoch: 1 [18240/60000 (30%)]\t training loss: 0.025740\n",
      "epoch: 1 [18560/60000 (31%)]\t training loss: 0.065141\n",
      "epoch: 1 [18880/60000 (31%)]\t training loss: 0.220227\n",
      "epoch: 1 [19200/60000 (32%)]\t training loss: 0.102033\n",
      "epoch: 1 [19520/60000 (33%)]\t training loss: 0.068922\n",
      "epoch: 1 [19840/60000 (33%)]\t training loss: 0.075009\n",
      "epoch: 1 [20160/60000 (34%)]\t training loss: 0.111961\n",
      "epoch: 1 [20480/60000 (34%)]\t training loss: 0.056665\n",
      "epoch: 1 [20800/60000 (35%)]\t training loss: 0.234118\n",
      "epoch: 1 [21120/60000 (35%)]\t training loss: 0.303591\n",
      "epoch: 1 [21440/60000 (36%)]\t training loss: 0.217894\n",
      "epoch: 1 [21760/60000 (36%)]\t training loss: 0.091958\n",
      "epoch: 1 [22080/60000 (37%)]\t training loss: 0.079766\n",
      "epoch: 1 [22400/60000 (37%)]\t training loss: 0.151057\n",
      "epoch: 1 [22720/60000 (38%)]\t training loss: 0.262819\n",
      "epoch: 1 [23040/60000 (38%)]\t training loss: 0.061579\n",
      "epoch: 1 [23360/60000 (39%)]\t training loss: 0.135419\n",
      "epoch: 1 [23680/60000 (39%)]\t training loss: 0.285402\n",
      "epoch: 1 [24000/60000 (40%)]\t training loss: 0.148586\n",
      "epoch: 1 [24320/60000 (41%)]\t training loss: 0.066807\n",
      "epoch: 1 [24640/60000 (41%)]\t training loss: 0.126747\n",
      "epoch: 1 [24960/60000 (42%)]\t training loss: 0.026213\n",
      "epoch: 1 [25280/60000 (42%)]\t training loss: 0.024073\n",
      "epoch: 1 [25600/60000 (43%)]\t training loss: 0.600073\n",
      "epoch: 1 [25920/60000 (43%)]\t training loss: 0.497171\n",
      "epoch: 1 [26240/60000 (44%)]\t training loss: 0.118145\n",
      "epoch: 1 [26560/60000 (44%)]\t training loss: 0.040906\n",
      "epoch: 1 [26880/60000 (45%)]\t training loss: 0.154461\n",
      "epoch: 1 [27200/60000 (45%)]\t training loss: 0.013285\n",
      "epoch: 1 [27520/60000 (46%)]\t training loss: 0.027993\n",
      "epoch: 1 [27840/60000 (46%)]\t training loss: 0.127872\n",
      "epoch: 1 [28160/60000 (47%)]\t training loss: 0.040515\n",
      "epoch: 1 [28480/60000 (47%)]\t training loss: 0.402136\n",
      "epoch: 1 [28800/60000 (48%)]\t training loss: 0.138493\n",
      "epoch: 1 [29120/60000 (49%)]\t training loss: 0.207102\n",
      "epoch: 1 [29440/60000 (49%)]\t training loss: 0.012119\n",
      "epoch: 1 [29760/60000 (50%)]\t training loss: 0.054411\n",
      "epoch: 1 [30080/60000 (50%)]\t training loss: 0.546068\n",
      "epoch: 1 [30400/60000 (51%)]\t training loss: 0.144434\n",
      "epoch: 1 [30720/60000 (51%)]\t training loss: 0.225871\n",
      "epoch: 1 [31040/60000 (52%)]\t training loss: 0.069757\n",
      "epoch: 1 [31360/60000 (52%)]\t training loss: 0.068556\n",
      "epoch: 1 [31680/60000 (53%)]\t training loss: 0.034509\n",
      "epoch: 1 [32000/60000 (53%)]\t training loss: 0.015917\n",
      "epoch: 1 [32320/60000 (54%)]\t training loss: 0.107069\n",
      "epoch: 1 [32640/60000 (54%)]\t training loss: 0.110502\n",
      "epoch: 1 [32960/60000 (55%)]\t training loss: 0.077687\n",
      "epoch: 1 [33280/60000 (55%)]\t training loss: 0.276489\n",
      "epoch: 1 [33600/60000 (56%)]\t training loss: 0.186835\n",
      "epoch: 1 [33920/60000 (57%)]\t training loss: 0.017603\n",
      "epoch: 1 [34240/60000 (57%)]\t training loss: 0.025609\n",
      "epoch: 1 [34560/60000 (58%)]\t training loss: 0.003528\n",
      "epoch: 1 [34880/60000 (58%)]\t training loss: 0.123900\n",
      "epoch: 1 [35200/60000 (59%)]\t training loss: 0.229518\n",
      "epoch: 1 [35520/60000 (59%)]\t training loss: 0.131734\n",
      "epoch: 1 [35840/60000 (60%)]\t training loss: 0.015819\n",
      "epoch: 1 [36160/60000 (60%)]\t training loss: 0.165748\n",
      "epoch: 1 [36480/60000 (61%)]\t training loss: 0.117925\n",
      "epoch: 1 [36800/60000 (61%)]\t training loss: 0.140046\n",
      "epoch: 1 [37120/60000 (62%)]\t training loss: 0.043650\n",
      "epoch: 1 [37440/60000 (62%)]\t training loss: 0.216800\n",
      "epoch: 1 [37760/60000 (63%)]\t training loss: 0.032769\n",
      "epoch: 1 [38080/60000 (63%)]\t training loss: 0.113341\n",
      "epoch: 1 [38400/60000 (64%)]\t training loss: 0.074898\n",
      "epoch: 1 [38720/60000 (65%)]\t training loss: 0.488738\n",
      "epoch: 1 [39040/60000 (65%)]\t training loss: 0.048389\n",
      "epoch: 1 [39360/60000 (66%)]\t training loss: 0.176396\n",
      "epoch: 1 [39680/60000 (66%)]\t training loss: 0.021329\n",
      "epoch: 1 [40000/60000 (67%)]\t training loss: 0.106253\n",
      "epoch: 1 [40320/60000 (67%)]\t training loss: 0.065340\n",
      "epoch: 1 [40640/60000 (68%)]\t training loss: 0.202225\n",
      "epoch: 1 [40960/60000 (68%)]\t training loss: 0.194045\n",
      "epoch: 1 [41280/60000 (69%)]\t training loss: 0.213245\n",
      "epoch: 1 [41600/60000 (69%)]\t training loss: 0.155805\n",
      "epoch: 1 [41920/60000 (70%)]\t training loss: 0.040492\n",
      "epoch: 1 [42240/60000 (70%)]\t training loss: 0.011083\n",
      "epoch: 1 [42560/60000 (71%)]\t training loss: 0.037179\n",
      "epoch: 1 [42880/60000 (71%)]\t training loss: 0.100338\n",
      "epoch: 1 [43200/60000 (72%)]\t training loss: 0.045283\n",
      "epoch: 1 [43520/60000 (73%)]\t training loss: 0.226100\n",
      "epoch: 1 [43840/60000 (73%)]\t training loss: 0.040024\n",
      "epoch: 1 [44160/60000 (74%)]\t training loss: 0.116498\n",
      "epoch: 1 [44480/60000 (74%)]\t training loss: 0.061347\n",
      "epoch: 1 [44800/60000 (75%)]\t training loss: 0.250636\n",
      "epoch: 1 [45120/60000 (75%)]\t training loss: 0.015089\n",
      "epoch: 1 [45440/60000 (76%)]\t training loss: 0.179538\n",
      "epoch: 1 [45760/60000 (76%)]\t training loss: 0.005873\n",
      "epoch: 1 [46080/60000 (77%)]\t training loss: 0.246703\n",
      "epoch: 1 [46400/60000 (77%)]\t training loss: 0.059748\n",
      "epoch: 1 [46720/60000 (78%)]\t training loss: 0.086515\n",
      "epoch: 1 [47040/60000 (78%)]\t training loss: 0.056783\n",
      "epoch: 1 [47360/60000 (79%)]\t training loss: 0.026905\n",
      "epoch: 1 [47680/60000 (79%)]\t training loss: 0.229662\n",
      "epoch: 1 [48000/60000 (80%)]\t training loss: 0.219784\n",
      "epoch: 1 [48320/60000 (81%)]\t training loss: 0.173513\n",
      "epoch: 1 [48640/60000 (81%)]\t training loss: 0.020131\n",
      "epoch: 1 [48960/60000 (82%)]\t training loss: 0.092622\n",
      "epoch: 1 [49280/60000 (82%)]\t training loss: 0.143768\n",
      "epoch: 1 [49600/60000 (83%)]\t training loss: 0.227249\n",
      "epoch: 1 [49920/60000 (83%)]\t training loss: 0.129910\n",
      "epoch: 1 [50240/60000 (84%)]\t training loss: 0.071571\n",
      "epoch: 1 [50560/60000 (84%)]\t training loss: 0.003748\n",
      "epoch: 1 [50880/60000 (85%)]\t training loss: 0.004240\n",
      "epoch: 1 [51200/60000 (85%)]\t training loss: 0.232011\n",
      "epoch: 1 [51520/60000 (86%)]\t training loss: 0.028602\n",
      "epoch: 1 [51840/60000 (86%)]\t training loss: 0.013641\n",
      "epoch: 1 [52160/60000 (87%)]\t training loss: 0.010407\n",
      "epoch: 1 [52480/60000 (87%)]\t training loss: 0.014092\n",
      "epoch: 1 [52800/60000 (88%)]\t training loss: 0.041886\n",
      "epoch: 1 [53120/60000 (89%)]\t training loss: 0.029681\n",
      "epoch: 1 [53440/60000 (89%)]\t training loss: 0.032927\n",
      "epoch: 1 [53760/60000 (90%)]\t training loss: 0.044958\n",
      "epoch: 1 [54080/60000 (90%)]\t training loss: 0.014901\n",
      "epoch: 1 [54400/60000 (91%)]\t training loss: 0.136652\n",
      "epoch: 1 [54720/60000 (91%)]\t training loss: 0.011173\n",
      "epoch: 1 [55040/60000 (92%)]\t training loss: 0.002030\n",
      "epoch: 1 [55360/60000 (92%)]\t training loss: 0.066842\n",
      "epoch: 1 [55680/60000 (93%)]\t training loss: 0.048196\n",
      "epoch: 1 [56000/60000 (93%)]\t training loss: 0.052259\n",
      "epoch: 1 [56320/60000 (94%)]\t training loss: 0.161982\n",
      "epoch: 1 [56640/60000 (94%)]\t training loss: 0.054209\n",
      "epoch: 1 [56960/60000 (95%)]\t training loss: 0.028114\n",
      "epoch: 1 [57280/60000 (95%)]\t training loss: 0.107114\n",
      "epoch: 1 [57600/60000 (96%)]\t training loss: 0.003919\n",
      "epoch: 1 [57920/60000 (97%)]\t training loss: 0.093449\n",
      "epoch: 1 [58240/60000 (97%)]\t training loss: 0.043330\n",
      "epoch: 1 [58560/60000 (98%)]\t training loss: 0.005689\n",
      "epoch: 1 [58880/60000 (98%)]\t training loss: 0.087195\n",
      "epoch: 1 [59200/60000 (99%)]\t training loss: 0.009148\n",
      "epoch: 1 [59520/60000 (99%)]\t training loss: 0.035150\n",
      "epoch: 1 [59840/60000 (100%)]\t training loss: 0.024602\n",
      "\n",
      "Test dataset: Overall Loss: 0.0478, Overall Accuracy: 9845/10000 (98%)\n",
      "\n"
     ]
    }
   ],
   "source": [
    "for epoch in range(1, 2):\n",
    "    train(model, device, train_dataloader, optimizer, epoch)\n",
    "    test(model, device, test_dataloader)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## run inference on trained model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGdCAYAAABU0qcqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAbSUlEQVR4nO3df2yV5f3/8Vcp9AjaHqylPa38sEWRTSw4JrVBGUpD2zkCSAw4XWAxMrCQAVOXblNgmtSxzBENw/2xwAziDxKBgKSbFlvmLBiqjDldR7EbRdoyMZxTihRGr+8ffD0fj7TgfTin79PyfCRX0nPf97v3m8s7fXmfc/dqknPOCQCAHtbPugEAwOWJAAIAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJgggAICJ/tYNfFVnZ6eOHDmi1NRUJSUlWbcDAPDIOae2tjbl5OSoX7/u73MSLoCOHDmiYcOGWbcBALhETU1NGjp0aLf7E+4tuNTUVOsWAAAxcLGf53ELoDVr1ui6667TFVdcoYKCAr377rtfq4633QCgb7jYz/O4BNArr7yiZcuWafny5Xrvvfc0duxYFRcX6+jRo/E4HQCgN3JxMGHCBFdWVhZ+ffbsWZeTk+MqKiouWhsMBp0kBoPBYPTyEQwGL/jzPuZ3QKdPn1ZdXZ2KiorC2/r166eioiLV1taed3xHR4dCoVDEAAD0fTEPoE8//VRnz55VVlZWxPasrCy1tLScd3xFRYX8fn948AQcAFwezJ+CKy8vVzAYDI+mpibrlgAAPSDmvweUkZGh5ORktba2RmxvbW1VIBA473ifzyefzxfrNgAACS7md0ApKSkaP368qqqqwts6OztVVVWlwsLCWJ8OANBLxWUlhGXLlmnu3Ln69re/rQkTJmj16tVqb2/XD3/4w3icDgDQC8UlgGbPnq3//ve/euKJJ9TS0qJx48apsrLyvAcTAACXryTnnLNu4stCoZD8fr91GwCASxQMBpWWltbtfvOn4AAAlycCCABgggACAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGCCAAIAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGCCAAIAmCCAAAAmCCAAgAkCCABgor91AwDi5957742q7tVXX/Vcc8stt3iu2bdvn+ca9B3cAQEATBBAAAATBBAAwAQBBAAwQQABAEwQQAAAEwQQAMAEAQQAMEEAAQBMEEAAABMEEADABAEEADDBYqSAgauvvtpzzerVqz3XTJw40XONJG3bts1zzccffxzVuXD54g4IAGCCAAIAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACRYjBQysXLnSc80DDzzguaazs9NzjST95S9/8VwzaNAgzzWhUMhzDfoO7oAAACYIIACAiZgH0IoVK5SUlBQxRo8eHevTAAB6ubh8BnTTTTfpzTff/L+T9OejJgBApLgkQ//+/RUIBOLxrQEAfURcPgM6cOCAcnJylJeXp/vvv1+HDh3q9tiOjg6FQqGIAQDo+2IeQAUFBVq/fr0qKyu1du1aNTY26o477lBbW1uXx1dUVMjv94fHsGHDYt0SACABxTyASktLde+99yo/P1/FxcXasWOHjh8/rldffbXL48vLyxUMBsOjqakp1i0BABJQ3J8OGDx4sEaNGqWGhoYu9/t8Pvl8vni3AQBIMHH/PaATJ07o4MGDys7OjvepAAC9SMwD6JFHHlFNTY3+/e9/65133tHMmTOVnJys++67L9anAgD0YjF/C+7w4cO67777dOzYMQ0ZMkS33367du/erSFDhsT6VACAXizmAfTyyy/H+lsCCa2oqMhzzYkTJzzXfPzxx55rfvCDH3iukaRRo0Z5rtmxY4fnmrvvvttzTXNzs+caJCbWggMAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGAiyTnnrJv4slAoJL/fb90G8LXV1dV5rhkxYoTnmttuu81zTXd/CDIeNm3a5Llm6NChnmsKCws918BGMBhUWlpat/u5AwIAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGCCAAIAmOhv3QAQD8nJyVHVvfbaa55r8vLyPNdMmzbNc01PrmwdjR07dniueeaZZzzXjBo1ynPNv/71L881iD/ugAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGCCAAIAmCCAAAAmCCAAgAkCCABgggACAJhgMVIkvHHjxnmuWb58eVTn+t73vue55qmnnvJc8/bbb3uuSXSfffaZ55rU1FTPNZMnT/Zcw2KkiYk7IACACQIIAGCCAAIAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACaSnHPOuokvC4VC8vv91m0ggaxevdpzzeLFi6M6V1NTk+ea4uJizzX19fWea/qitrY2zzV79uzxXFNUVOS5BpcuGAwqLS2t2/3cAQEATBBAAAATngNo165dmjZtmnJycpSUlKQtW7ZE7HfO6YknnlB2drYGDhyooqIiHThwIFb9AgD6CM8B1N7errFjx2rNmjVd7l+1apWeffZZPf/889qzZ4+uvPJKFRcX69SpU5fcLACg7/D8F1FLS0tVWlra5T7nnFavXq1f/OIXmj59uiTphRdeUFZWlrZs2aI5c+ZcWrcAgD4jpp8BNTY2qqWlJeKJE7/fr4KCAtXW1nZZ09HRoVAoFDEAAH1fTAOopaVFkpSVlRWxPSsrK7zvqyoqKuT3+8Nj2LBhsWwJAJCgzJ+CKy8vVzAYDI9ofg8DAND7xDSAAoGAJKm1tTVie2tra3jfV/l8PqWlpUUMAEDfF9MAys3NVSAQUFVVVXhbKBTSnj17VFhYGMtTAQB6Oc9PwZ04cUINDQ3h142Njdq3b5/S09M1fPhwLVmyRE899ZRuuOEG5ebm6vHHH1dOTo5mzJgRy74BAL2c5wDau3ev7rzzzvDrZcuWSZLmzp2r9evX67HHHlN7e7vmz5+v48eP6/bbb1dlZaWuuOKK2HUNAOj1WIwUPWrFihWea6ZMmeK5Ji8vz3ONJN11112ea1hYNHosRtq3sRgpACAhEUAAABMEEADABAEEADBBAAEATBBAAAATBBAAwAQBBAAwQQABAEwQQAAAEwQQAMAEAQQAMEEAAQBMeP5zDMAXhg4d6rlm/vz5nmuysrI81+zbt89zjcTK1r1BNH81edCgQVGd6+TJk1HV4evhDggAYIIAAgCYIIAAACYIIACACQIIAGCCAAIAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJgggAIAJFiNF1AoKCjzXRLOw6P/+9z/PNU8//bTnGvQO0SyCe/XVV0d1LhYjjS/ugAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGCCAAIAmCCAAAAmCCAAgAkCCABgggACAJhgMVJEraioqEfOc/r0ac81mzZtikMnuJDx48d7rklJSfFc8+GHH3qu+eSTTzzXIP64AwIAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGCCxUgRtT//+c+ea+bPn++5prKy0nMNel5+fr7nmv79+RF0OeMOCABgggACAJjwHEC7du3StGnTlJOTo6SkJG3ZsiVi/7x585SUlBQxSkpKYtUvAKCP8BxA7e3tGjt2rNasWdPtMSUlJWpubg6Pl1566ZKaBAD0PZ4/ASwtLVVpaekFj/H5fAoEAlE3BQDo++LyGVB1dbUyMzN14403auHChTp27Fi3x3Z0dCgUCkUMAEDfF/MAKikp0QsvvKCqqir96le/Uk1NjUpLS3X27Nkuj6+oqJDf7w+PYcOGxbolAEACivlD+HPmzAl/ffPNNys/P18jR45UdXW1pkyZct7x5eXlWrZsWfh1KBQihADgMhD3x7Dz8vKUkZGhhoaGLvf7fD6lpaVFDABA3xf3ADp8+LCOHTum7OzseJ8KANCLeH4L7sSJExF3M42Njdq3b5/S09OVnp6ulStXatasWQoEAjp48KAee+wxXX/99SouLo5p4wCA3s1zAO3du1d33nln+PUXn9/MnTtXa9eu1f79+/XHP/5Rx48fV05OjqZOnaonn3xSPp8vdl0DAHo9zwE0efJkOee63f+nP/3pkhpC73HgwIEeOc9TTz3VI+fBpfnmN7/ZI+f56KOPeuQ8iD/WggMAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGCCAAIAmIj5n+QGYm3UqFGea/72t7/FoZPLx5gxYzzXPPDAA55rOjs7Pde8/vrrnmuQmLgDAgCYIIAAACYIIACACQIIAGCCAAIAmCCAAAAmCCAAgAkCCABgggACAJgggAAAJgggAIAJAggAYILFSJHwbrnlFs81mzZtikMntgKBgOea8ePHR3WutWvXeq7JzMz0XPPJJ594rqmsrPRcg8TEHRAAwAQBBAAwQQABAEwQQAAAEwQQAMAEAQQAMEEAAQBMEEAAABMEEADABAEEADBBAAEATBBAAAATLEaKhDdmzBjrFmIuKyvLc8327ds910SzkGtP+vnPf27dAgxxBwQAMEEAAQBMEEAAABMEEADABAEEADBBAAEATBBAAAATBBAAwAQBBAAwQQABAEwQQAAAEwQQAMAEi5Eiav/4xz8810SzoGZJSYnnmt/85jeea6KVkpLiueZHP/qR55rk5GTPNdHq6OjwXPPcc895rtmwYYPnGvQd3AEBAEwQQAAAE54CqKKiQrfeeqtSU1OVmZmpGTNmqL6+PuKYU6dOqaysTNdcc42uuuoqzZo1S62trTFtGgDQ+3kKoJqaGpWVlWn37t164403dObMGU2dOlXt7e3hY5YuXapt27Zp06ZNqqmp0ZEjR3TPPffEvHEAQO/m6SGEysrKiNfr169XZmam6urqNGnSJAWDQf3hD3/Qxo0bddddd0mS1q1bp2984xvavXu3brvttth1DgDo1S7pM6BgMChJSk9PlyTV1dXpzJkzKioqCh8zevRoDR8+XLW1tV1+j46ODoVCoYgBAOj7og6gzs5OLVmyRBMnTtSYMWMkSS0tLUpJSdHgwYMjjs3KylJLS0uX36eiokJ+vz88hg0bFm1LAIBeJOoAKisr0wcffKCXX375khooLy9XMBgMj6ampkv6fgCA3iGqX0RdtGiRtm/frl27dmno0KHh7YFAQKdPn9bx48cj7oJaW1sVCAS6/F4+n08+ny+aNgAAvZinOyDnnBYtWqTNmzdr586dys3Njdg/fvx4DRgwQFVVVeFt9fX1OnTokAoLC2PTMQCgT/B0B1RWVqaNGzdq69atSk1NDX+u4/f7NXDgQPn9fj344INatmyZ0tPTlZaWpsWLF6uwsJAn4AAAETwF0Nq1ayVJkydPjti+bt06zZs3T5L029/+Vv369dOsWbPU0dGh4uJi/e53v4tJswCAviPJOeesm/iyUCgkv99v3QbipLvPAi/k9ddf91wzbtw4zzV90d///veo6h5++GHPNe+8805U50LfFQwGlZaW1u1+1oIDAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGCCAAIAmCCAAAAmCCAAgAkCCABgggACAJhgNWwkvMzMTM81q1evjupcs2fPjqrOqw0bNniuefLJJz3XfPbZZ55rLqUO+DJWwwYAJCQCCABgggACAJgggAAAJgggAIAJAggAYIIAAgCYIIAAACYIIACACQIIAGCCAAIAmCCAAAAmWIwUABAXLEYKAEhIBBAAwAQB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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "test_samples = enumerate(test_dataloader)\n",
    "b_i, (sample_data, sample_targets) = next(test_samples)\n",
    "\n",
    "plt.imshow(sample_data[0][0], cmap='gray', interpolation='none')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model prediction is : 0\n",
      "Ground truth is : 0\n"
     ]
    }
   ],
   "source": [
    "print(f\"Model prediction is : {model(sample_data).data.max(1)[1][0]}\")\n",
    "print(f\"Ground truth is : {sample_targets[0]}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## captum tools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "captum_input = sample_data[0].unsqueeze(0)\n",
    "captum_input.requires_grad = True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAeEAAAH4CAYAAAB9k1VdAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAVpUlEQVR4nO3df6yWdf348df5QYDILwVSIEGC4RjURGamQFA6ClFhaM2QgZJImWADmrMQtELRERSTiWYCkeQgNAq0WvEjlnNLpyhqhgIjMZEDjCM/TDj354++nK9HROHcR1+cw+PxF1739b7u131v7On73PfhKikUCoUAAD5xpdkDAMDJSoQBIIkIA0ASEQaAJCIMAElEGACSiDAAJBFhAEgiwgCQRIThI0ybNi1KSkpqtXb+/PlRUlISmzdvrtuh3mPz5s1RUlIS8+fP/9ieA/h4iDAN1oYNG+Kaa66JDh06ROPGjaN9+/YxYsSI2LBhQ/ZoKVavXh0lJSWxdOnS7FGA/0eEaZCWLVsWvXv3jr/85S9x7bXXxty5c2PMmDGxatWq6N27dzz66KPHfK0f/vCHsX///lrNMXLkyNi/f3906tSpVuuBhq08ewCoa6+++mqMHDkyunTpEmvXro22bdtWPzZhwoTo169fjBw5MtavXx9dunQ56nX27t0bzZo1i/Ly8igvr91flbKysigrK6vVWqDhsxOmwbnnnnti3759cf/999cIcEREmzZtYt68ebF37964++67q48f/tz3xRdfjG9+85vRunXr6Nu3b43H3mv//v0xfvz4aNOmTTRv3jwuv/zyeP3116OkpCSmTZtWfd4HfSbcuXPnGDJkSKxbty7OP//8aNKkSXTp0iUWLlxY4zl27twZkyZNil69esWpp54aLVq0iK997Wvx3HPP1dE79f9f2yuvvBLXXHNNtGzZMtq2bRtTpkyJQqEQW7dujSuuuCJatGgRZ5xxRsycObPG+v/+979x2223xXnnnRctW7aMZs2aRb9+/WLVqlVHPFdFRUWMHDkyWrRoEa1atYpRo0bFc88994GfZ7/88stx5ZVXxmmnnRZNmjSJPn36xPLly+vsdcOJQoRpcH7/+99H586do1+/fh/4eP/+/aNz586xYsWKIx676qqrYt++fTF9+vS4/vrrj/oco0ePjjlz5sTgwYNjxowZ0bRp07j00kuPecaNGzfGlVdeGZdccknMnDkzWrduHaNHj67xefVrr70Wjz32WAwZMiR++tOfxuTJk+P555+PL33pS7Ft27Zjfq5j8Y1vfCOqqqrirrvuii984Qvx4x//OGbPnh2XXHJJdOjQIWbMmBFdu3aNSZMmxdq1a6vX7dmzJ37xi1/EgAEDYsaMGTFt2rR46623YtCgQfHss89Wn1dVVRWXXXZZLF68OEaNGhU/+clP4o033ohRo0YdMcuGDRviggsuiJdeeiluueWWmDlzZjRr1iyGDh16XB8jQL1QgAZk9+7dhYgoXHHFFR963uWXX16IiMKePXsKhUKhMHXq1EJEFK6++uojzj382GFPP/10ISIKN998c43zRo8eXYiIwtSpU6uPPfTQQ4WIKGzatKn6WKdOnQoRUVi7dm31se3btxcaN25cmDhxYvWxAwcOFA4dOlTjOTZt2lRo3Lhx4Y477qhxLCIKDz300Ie+5lWrVhUiorBkyZIjXtvYsWOrjx08eLDQsWPHQklJSeGuu+6qPr5r165C06ZNC6NGjapx7jvvvFPjeXbt2lX49Kc/Xbjuuuuqj/32t78tRERh9uzZ1ccOHTpU+PKXv3zE7F/5ylcKvXr1Khw4cKD6WFVVVeHCCy8sdOvW7UNfI9Q3dsI0KJWVlRER0bx58w897/Dje/bsqXF83LhxH/kcTzzxREREfOc736lx/KabbjrmOXv06FFjp962bdvo3r17vPbaa9XHGjduHKWl//sreujQoaioqIhTTz01unfvHs8888wxP9ex+Na3vlX957KysujTp08UCoUYM2ZM9fFWrVodMWNZWVl86lOfioj/7XZ37twZBw8ejD59+tSY8YknnohGjRrV+OlCaWlp3HjjjTXm2LlzZ/z1r3+Nr3/961FZWRk7duyIHTt2REVFRQwaNCj+9a9/xeuvv16nrx0y+WIWDcrhuB6O8dEcLdZnn332Rz7Hli1borS09Ihzu3btesxznnXWWUcca926dezatav6v6uqquJnP/tZzJ07NzZt2hSHDh2qfuz0008/5ueqzTwtW7aMJk2aRJs2bY44XlFRUePYggULYubMmfHyyy/Hu+++W338ve/Pli1b4swzz4xTTjmlxtr3v2cbN26MQqEQU6ZMiSlTpnzgrNu3b48OHToc+4uDE5gI06C0bNkyzjzzzFi/fv2Hnrd+/fro0KFDtGjRosbxpk2bfpzjVTvaN6YLhUL1n6dPnx5TpkyJ6667Ln70ox/FaaedFqWlpXHzzTdHVVXVxz7Pscy4aNGiGD16dAwdOjQmT54c7dq1i7Kysrjzzjvj1VdfPe45Dr+uSZMmxaBBgz7wnOP5nx040YkwDc6QIUPigQceiHXr1lV/w/m9/va3v8XmzZvjhhtuqNX1O3XqFFVVVbFp06bo1q1b9fGNGzfWeuYPsnTp0hg4cGA8+OCDNY7v3r37iB1qlqVLl0aXLl1i2bJlNb5BPnXq1BrnderUKVatWhX79u2rsRt+/3t2+FfGGjVqFBdffPHHODmcGHwmTIMzefLkaNq0adxwww1H/Oh0586dMW7cuDjllFNi8uTJtbr+4R3a3LlzaxyfM2dO7QY+irKyshq7zoiIJUuWnFCfiR7eLb93zqeeeiqefPLJGucNGjQo3n333XjggQeqj1VVVcW9995b47x27drFgAEDYt68efHGG28c8XxvvfVWXY4P6eyEaXC6desWCxYsiBEjRkSvXr1izJgxcfbZZ8fmzZvjwQcfjB07dsTixYvjs5/9bK2uf95558Xw4cNj9uzZUVFRERdccEGsWbMmXnnllYiIWv870+83ZMiQuOOOO+Laa6+NCy+8MJ5//vn49a9//aH/wMgnbciQIbFs2bIYNmxYXHrppbFp06a47777okePHvH2229Xnzd06NA4//zzY+LEibFx48Y455xzYvny5bFz586IqPme3XvvvdG3b9/o1atXXH/99dGlS5d4880348knn4x///vfdfp70pBNhGmQrrrqqjjnnHPizjvvrA7v6aefHgMHDoxbb701evbsWdT1Fy5cGGeccUYsXrw4Hn300bj44ovjkUceie7du0eTJk3q5DXceuutsXfv3nj44YfjkUceid69e8eKFSvilltuqZPr14XRo0fHf/7zn5g3b1788Y9/jB49esSiRYtiyZIlsXr16urzysrKYsWKFTFhwoRYsGBBlJaWxrBhw2Lq1Klx0UUX1XjPevToEf/4xz/i9ttvj/nz50dFRUW0a9cuzj333LjtttsSXiV8fEoK7/95F1Arzz77bJx77rmxaNGiGDFiRPY49cJjjz0Ww4YNi3Xr1sVFF12UPQ584nwmDLXwQTd0mD17dpSWlkb//v0TJjrxvf89O3ToUMyZMyda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",
      "text/plain": [
       "<Figure size 600x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "orig_image = np.tile(np.transpose((sample_data[0].cpu().detach().numpy() / 2) + 0.5, (1, 2, 0)), (1,1,3))\n",
    "# tmp = np.transpose((sample_data[0].cpu().detach().numpy() / 2) + 0.5, (1, 2, 0))\n",
    "# orig_image = np.concatenate([tmp, np.zeros(tmp.shape), np.zeros(tmp.shape)], axis=2)\n",
    "_ = viz.visualize_image_attr(None, orig_image, cmap='gray', method=\"original_image\", title=\"Original Image\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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du/erT179mjYsGH68MMP9emnn0aNc/311zfo7C49PT3qZ9i9e7cKCgpUVlamTZs2RS67+uqr9X//93/avHlzZNv8+fPVqVMnDRkyRJK0fPnyyJllzRx3796tYDCoAQMGaOXKlZKknTt3at26dRo/frxycnIix/vBD36gnj17HnHONWuXmZkZtf29995T27Zto/7s2bMnap8hQ4bEHaP2Ouzdu1f79+9XQUGB3n777cj2pUuXSpJuueWWqNpbb731iHNu6NrUdtNNN0X9v6CgQFu2bDniWOnp6UpNTdWqVau0d+/eI+4PNBYCFiZqgrMmaOtTN4h/+MMfKicnJ+rp14ULF6pv37469dRTJUkfffSRnHO6++67YwKkqKhIkvT5559HjXPKKac0aN7r16/XZZddppycHGVnZ6tt27b6yU9+Iknav39/ZL/Ro0crFApp/vz5kcuef/55jRs3LvIa6IcffihJOv/882PmuWzZssgcP/74Y0lS9+7dY+Zz2mmnHXHONWv31VdfRW3v1q2bli9fruXLl6uwsDBubX3r8vzzz+vss89WWlqaWrduHXkKtvYafPzxx0pKSlLXrl0TnnND16ZGWlpazOv4rVq1alBghkIhPfjgg3rxxRfVrl07DR48WFOnTlVJSckRawE/eBcxTOTk5CgvL0/vvvvuYfd799131aFDB2VnZ0v65sGw5nXUWbNmadeuXXr99dc1ZcqUSE04HJYk/eIXv9CwYcPiHrdbt25R/699Rlafffv2aciQIcrOzta9996rrl27Ki0tTW+//bbuvPPOyLjSNw/ul1xyiebPn69f//rXKi4uVnl5eSSMa89z3rx5at++fcx4ycmNc/fr0aOHJOn999/XqFGjItszMzM1dOhQSd+8ThtPvHV57bXXNHLkSA0ePFizZs1SXl6eUlJSNGfOHP3pT39qlDknujZ+34F86623asSIEVqyZIlefvll3X333br//vv1yiuvqF+/fr6ODdSHgIWZSy65RLNnz9bq1as1aNCgmMtfe+01bdu2TTfeeGPU9tGjR+upp57SihUrtHHjRjnnIk8PS4p8pCclJSUSII1h1apV2rNnjxYtWqTBgwdHtm/dujXu/ldffbVGjRqlN998U/Pnz1e/fv3Uq1evyOU1Z3a5ubmHnefJJ58s6buzuto++OCDI867oKBAOTk5WrBggf7jP/5DSUn+npj6y1/+orS0NL388stRn1udM2dOzLzD4bA2b94cddbakDk3dG0SEe/d03XH/PnPf66f//zn+vDDD9W3b1/NmDFDf/zjHxtlfKAuniKGmdtvv13p6em68cYbY177+/LLL3XTTTepRYsWuv3226MuGzp0qFq3bq2FCxdq4cKFOuuss6KeyszNzdV5552nxx9/XDt37owZN97HZxqi5izJORfZVlFRoVmzZsXd/6KLLlKbNm304IMP6tVXX406e5WkYcOGKTs7W1OmTFFlZWW988zLy1Pfvn311FNPRT0Fu3z5cm3YsOGI827RooXuuOMOvf/++5o8eXLU/GvE21afYDCoQCAQ9dGkbdu2acmSJVH7XXTRRZKk3/3ud1HbH3rooSOO0dC1SUSLFi0kffNMRG1lZWVRH5uSvgnbrKwslZeXJzwO0FCcwcJM9+7d9dRTT2ncuHHq06dPzDc57d69W3/+859jXsNLSUnR5ZdfrgULFujgwYOaPn16zLFnzpypQYMGqU+fPrr++uvVpUsX7dq1S2vWrNGOHTv0zjvvJDzfgQMHqlWrVho/frxuueUWBQIBzZs3r95wSklJ0VVXXaVHH31UwWBQY8aMibo8Oztbjz32mAoLC3XGGWfoqquuUtu2bfXJJ5/ohRde0LnnnqtHH31UknT//fdr+PDhGjRokP793/9dX375pR555BH16tUr5rXVeCZPnqyNGzdq2rRpkY/8dOzYUXv37tXbb7+tZ599Vrm5uQ36Eonhw4frt7/9rX74wx9q7Nix+vzzzzVz5kx169Yt6in/vn37asyYMZo1a5b279+vgQMHasWKFfroo4+OOEYia9NQ6enp6tmzpxYuXKhTTz1VrVu3Vu/evVVVVaULLrhAV155pXr27Knk5GQtXrxYu3bt0lVXXZXQGEBCmvItzDgxvPvuu27MmDEuLy/PpaSkuPbt27sxY8a49957r96a5cuXO0kuEAi47du3x91n8+bN7uqrr3bt27d3KSkprkOHDu6SSy5xxcXFkX1qPh7y5ptvxtTH+5jO66+/7s4++2yXnp7u8vPz3R133OFefvnlqI/f1PbGG284Se7CCy+s92dZuXKlGzZsmMvJyXFpaWmua9eu7pprrnH//Oc/o/b7y1/+4k4//XQXCoVcz5493aJFi9z48eOP+DGd2hYvXuwu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ELAAABggYAEAMEDAAgBggIAFAMAAAQsAgAECFgAAAwQsAAAGCFgAAAzQru44kOSj/Znkr4XZnj17fI2dlur9d7xlK1Z6rvXTbk6Sgj7qk4Pef+aD5dWeayXJz00lPTXoa+zqsPcbWuuT2niuDSX7O4/Yv/dL78X+bma+1sxPa0OfHTB9tcA8nnAGCwCAAQIWAAADBCwAAAYIWAAADBCwAAAYIGABADBAwAIAYICABQDAAAELAIABAhYAAAMELAAABghYAAAMELAAABggYAEAMEDAAgBggH6wxwg//Rebsvdi2GfjyOqw99r2uW091+7cWeJ9YEnJQe+LfqjSe0/X0q8rPddKUijF++/UKT762EpSWx/XV+/efTzX5mSmeK6VpC0ffei51k/fYMnffZuerE2PM1gAAAwQsAAAGCBgAQAwQMACAGCAgAUAwAABCwCAAQIWAAADBCwAAAYIWAAADBCwAAAYIGABADBAwAIAYICABQDAAAELAIAB2tUdI5qytZTz0XIuoKZrx5Xbrr3n2lDKeu8DSwr7aLOXmuz999rsFv5ar7XMzvJcm5+f52vsy0aN9FybkZnpuXbf/gOeayXpX37a1SX5u38k+biDNNcWmMcTzmABADBAwAIAYICABQDAAAELAIABAhYAAAMELAAABghYAAAMELAAABggYAEAMEDAAgBggIAFAMAAAQsAgAECFgAAAwQsAAAGaFcH+ek4Vx320RNLknyUZ7U8yXNteaWPfnOSkn20Ifvax9jtWud4rpWksePGea5NyWzta+ywjzZ9AR/9015dtdJzrSQFfYztt50jLeeaN85gAQAwQMACAGCAgAUAwAABCwCAAQIWAAADBCwAAAYIWAAADBCwAAAYIGABADBAwAIAYICABQDAAAELAIABAhYAAAMELAAABghYAAAM0A/2GNGUfR/9jP3FF5/7GnvDpk2ea08/rbvn2lGXXOy5VpL2fFXuuTYtNcVz7ZBzB3iulaTKau+1qT76uUrSwUMVnmtf/Nsqz7VvvLXWc60khXz+3DhxccsBAMAAAQsAgAECFgAAAwQsAAAGCFgAAAwQsAAAGCBgAQAwQMACAGCAgAUAwAABCwCAAQIWAAADBCwAAAYIWAAADBCwAAAYoF3dccBPuzlJ8tntzpelLzzvuXbcuHGeawecfbbnWkk6VOG975uf9oIpyUHvxZLKKio9127aut3X2H97+UXPtQf2lHiu9dturirs/Q6WnNSU9y40Nc5gAQAwQMACAGCAgAUAwAABCwCAAQIWAAADBCwAAAYIWAAADBCwAAAYIGABADBAwAIAYICABQDAAAELAIABAhYAAAMELAAABghYAAAM0A/2GOGnR6hf1WEfxT7nffCrg55rn5zztOfa8y640HOtJJ3es5fn2lCK999r1657x3OtJC1bsdJ7cVWFr7G/3P+V59pDld7772aE/D3MJQe938h992qmnWyzxhksAAAGCFgAAAwQsAAAGCBgAQAwQMACAGCAgAUAwAABCwCAAQIWAAADBCwAAAYIWAAADBCwAAAYIGABADBAwAIAYICABQDAAO3qjgN+W2L5accVDvsbvLzKexuyykPe2589W1zsuVaSqqqf8VybHPT+e22Sz/ZlwSTvY5f7aBknSdnpKZ5rM9K8P1Sl+lhvv2g3d2LjDBYAAAMELAAABghYAAAMELAAABggYAEAMEDAAgBggIAFAMAAAQsAgAECFgAAAwQsAAAGCFgAAAwQsAAAGCBgAQAwQMACAGCAdnXw1XIuyWf/tLSkoOfa1GTv886Q93Elqara+9jJPtasymd7wCQf/dNCyf5+H0/x0RZRTdj2jZZz8IozWAAADBCwAAAYIGABADBAwAIAYICABQDAAAELAIABAhYAAAMELAAABghYAAAMELAAABggYAEAMEDAAgBggIAFAMAAAQsAgAECFgAAA/SDPQ747VcZaMKGl85He1M/vU3DfgaWFPTR09XPevtsyeqrr2py0N/gftY84GPi9HNFU+EMFgAAAwQsAAAGCFgAAAwQsAAAGCBgAQAwQMACAGCAgAUAwAABCwCAAQIWAAADBCwAAAYIWAAADBCwAAAYIGABADBAwAIAYIB2dWhSTk3UwsxP3zb5a4Hm52f2OW1fP7ffFn9+2gsCzRFnsAAAGCBgAQAwQMACAGCAgAUAwAABCwCAAQIWAAADBCwAAAYIWAAADBCwAAAYIGABADBAwAIAYICABQDAAAELAIABAhYAAAMELAAABugHiybVVD1Cm7I1qd9etE2luc4baCqcwQIAYICABQDAAAELAIABAhYAAAMELAAABghYAAAMELAAABggYAEAMEDAAgBggIAFAMAAAQsAgAECFgAAAwQsAAAGGr2bjnNOklReXt7YhwYAoNHV5FVNfjWWgGvkI+7YsUOdOnVqzEMCAGBu+/bt6tixY6Mdr9EDNhwO67PPPlNWVpYCTdl0EwCABnDOqbS0VPn5+UpKarxXThs9YAEAAG9yAgDABAELAIABAhYAAAMELAAABghYAAAMELAAABho9G9ykqRDhw6poqLC4tAAADS61NRUpaWlNeoxGz1gDx06pFNOOUUlJSWNfWgAAEy0b99eW7dubdSQbfSAraioUElJibZs267s7Gw5ffs9FrW+zsLV/ZeLuvi7S1ycbTV/x/l6DFfnHy7OpS7uPOLXHH7u9W1oQJ2PsWLXKXZjg8eKU1N7DWv2i6qts8iuTk3MGIcZP9518d2xYmfpFPtdoa7OcWqOH++24Nx3l9cdv9aw9Y9Va6ldvJ8r7ljR84rZL+48Y8ets1vUPjFj1Vq76No46173+ox3G3P1rWf8ebq6O8ZcHvMIEDWPmOuz1oNB9NwPs04NvCx2rHiXfTenqP3jzjP++N8eJaou7n03avzYK772MeI+ZsTeGfyNW+9YLt7i1R5Edf5R67J69osc7zCX1d4n5kaZ6HG/O175oYOa/strVFFRcWwHbI3s7OwTJmBj536EusYeK+46eRsr6nYZ/VD5zb/rLLKrU/Pdtrp36tjxj6WAjYwftX+dsVz8/eretlzM5Ypez6h1ijfP6HVvzgEbb6zokIidR3MJ2AaPH+fnjvz/sOMf/hjHdsC62sV1foja+8U73mEua7TjxjmeAd7kBACAAQIWAAADBCwAAAYIWAAADBCwAAAYIGABADBAwAIAYICABQDAAAELAIABAhYAAAMELAAABghYAAAMELAAABggYAEAMEDAAgBggIAFAMAAAQsAgIFkqwMfOHBAkuRiOszX/ud3l9XtJ++id6y197d/x2lAH9PgPl513HnErzn83Ovb0IA6H2PFrlPsxgaPFaem9hrW7BdVW2eRXZ2amDEOM3686+K7Y8XO0klyda54V+c4NcePd1tw7rvL645fa9j6x6q11C7ezxV3rOh5xewXd56x49bZLWqfmLFqrV10bZx1r3t9xruNufrWM/48Xd0dYy6PeQSImkfM9VnrwSB67odZpwZeFjtWvMu+m1PU/nHnGX/8b48SVRf3vhs1fuwVX/sYcR8zYu8M/satdywXb/FqD6I6/6h1WT37RY53mMtq7xNzo0z0uN8dr/xQmSw0esA655SZmakunTs19qEBADCRmZkZ9xcjPxo9YAOBgL766itt375d2dnZjX34E9aBAwfUqVMn1rWRsa42WFcbrKuNmnUNBAKNelyzp4izs7O5ARhgXW2wrjZYVxusa/PAm5wAADBAwAIAYKDRAzYUCqmoqEihUKixD31CY11tsK42WFcbrKsNq3UNuMZ+2xQAAOApYgAALBCwAAAYIGABADBAwAIAYMBTwM6cOVOdO3dWWlqaBgwYoDfeeOOw+z/77LPq0aOH0tLS1KdPHy1dutTTZI93iazr7NmzVVBQoFatWqlVq1YaOnToEa+HE1Wit9caCxYsUCAQ0KWXXmo7wWYq0XXdt2+fJk6cqLy8PIVCIZ166qk8FsSR6Lo+9NBDOu2005Senq5OnTpp0qRJOnTo0FGabfPw97//XSNGjFB+fr4CgYCWLFlyxJpVq1bpjDPOUCgUUrdu3TR37tzEB3YJWrBggUtNTXX//d//7davX++uv/5617JlS7dr1664+7/++usuGAy6qVOnug0bNrhf/epXLiUlxb333nuJDn1cS3Rdx44d62bOnOnWrl3rNm7c6K655hqXk5PjduzYcZRnfmxLdF1rbN261XXo0MEVFBS4UaNGHZ3JNiOJrmt5ebk788wz3cUXX+xWr17ttm7d6latWuXWrVt3lGd+bEt0XefPn+9CoZCbP3++27p1q3v55ZddXl6emzRp0lGe+bFt6dKl7q677nKLFi1yktzixYsPu/+WLVtcixYt3G233eY2bNjgHnnkERcMBt1LL72U0LgJB+xZZ53lJk6cGPl/dXW1y8/Pd/fff3/c/a+88ko3fPjwqG0DBgxwN954Y6JDH9cSXde6qqqqXFZWlnvqqaesptgseVnXqqoqN3DgQPeHP/zBjR8/noCNI9F1feyxx1yXLl1cRUXF0Zpis5Touk6cONGdf/75Udtuu+02d+6555rOszlrSMDecccdrlevXlHbRo8e7YYNG5bQWAk9RVxRUaG33npLQ4cOjWxLSkrS0KFDtWbNmrg1a9asidpfkoYNG1bv/iciL+taV1lZmSorK9W6dWuraTY7Xtf13nvvVW5urq677rqjMc1mx8u6/vWvf9U555yjiRMnql27durdu7emTJmi6urqozXtY56XdR04cKDeeuutyNPIW7Zs0dKlS3XxxRcflTkfrxortxL6sv/du3erurpa7dq1i9rerl07bdq0KW5NSUlJ3P1LSkoSmujxzMu61nXnnXcqPz8/5kZxIvOyrqtXr9aTTz6pdevWHYUZNk9e1nXLli165ZVXNG7cOC1dulQfffSRJkyYoMrKShUVFR2NaR/zvKzr2LFjtXv3bg0aNEjOOVVVVemmm27SL3/5y6Mx5eNWfbl14MABff3110pPT2/QcXgX8XHggQce0IIFC7R48WKlpaU19XSardLSUhUWFmr27Nlq06ZNU0/nuBIOh5Wbm6snnnhC/fv31+jRo3XXXXfp97//fVNPrVlbtWqVpkyZolmzZuntt9/WokWL9MILL+i+++5r6qlBCZ7BtmnTRsFgULt27YravmvXLrVv3z5uTfv27RPa/0TkZV1rTJ8+XQ888ID+9re/6fvf/77lNJudRNd18+bN2rZtm0aMGBHZFg6HJUnJycn64IMP1LVrV9tJNwNebq95eXlKSUlRMBiMbDv99NNVUlKiiooKpaamms65OfCyrnfffbcKCwv105/+VJLUp08fHTx4UDfccIPuuusuJSVxDuVFfbmVnZ3d4LNXKcEz2NTUVPXv318rVqyIbAuHw1qxYoXOOeecuDXnnHNO1P6StHz58nr3PxF5WVdJmjp1qu677z699NJLOvPMM4/GVJuVRNe1R48eeu+997Ru3brIn5EjR+rf/u3ftG7dOnXq1OloTv+Y5eX2eu655+qjjz6K/MIiSf/617+Ul5dHuH7Ly7qWlZXFhGjNLzGOr5n3rNFyK7H3X33zNvJQKOTmzp3rNmzY4G644QbXsmVLV1JS4pxzrrCw0E2ePDmy/+uvv+6Sk5Pd9OnT3caNG11RUREf04kj0XV94IEHXGpqqisuLnY7d+6M/CktLW2qH+GYlOi61sW7iONLdF0/+eQTl5WV5W6++Wb3wQcfuOeff97l5ua6//zP/2yqH+GYlOi6FhUVuaysLPfnP//ZbdmyxS1btsx17drVXXnllU31IxyTSktL3dq1a93atWudJPfb3/7WrV271n388cfOOecmT57sCgsLI/vXfEzn9ttvdxs3bnQzZ848Oh/Tcc65Rx55xH3ve99zqamp7qyzznL/+7//G7lsyJAhbvz48VH7P/PMM+7UU091qamprlevXu6FF17wMuxxL5F1Pfnkk52kmD9FRUVHf+LHuERvr7URsPVLdF3/8Y9/uAEDBrhQKOS6dOni/uu//stVVVUd5Vkf+xJZ18rKSnfPPfe4rl27urS0NNepUyc3YcIEt3fv3qM/8WPYypUr4z5e1qzl+PHj3ZAhQ2Jq+vbt61JTU12XLl3cnDlzEh6XdnUAABjgFXAAAAwQsAAAGCBgAQAwQMACAGCAgAUAwAABCwCAAQIWAAADBCwAAAYIWAAADBCwAAAYIGABADBAwAIAYOD/A5O9q4yNtWqcAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 600x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "saliency = Saliency(model)\n",
    "gradients = saliency.attribute(captum_input, target=sample_targets[0].item())\n",
    "gradients = np.reshape(gradients.squeeze().cpu().detach().numpy(), (28, 28, 1))\n",
    "_ = viz.visualize_image_attr(gradients, orig_image, method=\"blended_heat_map\", sign=\"absolute_value\",\n",
    "                          show_colorbar=True, title=\"Overlayed Gradients\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAaAAAAGdCAYAAABU0qcqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAgEklEQVR4nO3de2zV9f3H8ddpaQ8V2lNL6U0KFlQwclnGsCMqc6MBusSIksXbEliMBlaIyJyORUW3Jd1YtvlzY/rPAjMRb4tANBuJgi1xAwwIYWRaaVcFRlsE7Dm90As9398fxG5Hbn4+np53W56P5JvQc86L8+m339NXvz3nvBsKgiAQAAAplma9AADA5YkCAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgIkR1gv4ong8rmPHjik7O1uhUMh6OQAAR0EQqK2tTSUlJUpLu/B5zqAroGPHjqm0tNR6GQCAr+jIkSMaN27cBa8fdAWUnZ1tvQRgUErlbwR8JnRlZmY6Z+LxuHPmzJkzzhnYuNT38wF7DmjdunW6+uqrNXLkSJWXl+u99977Ujl+7QacXygUYvPcYONS+35ACuiVV17RqlWrtGbNGr3//vuaMWOG5s+fr+PHjw/E3QEAhqDQQEzDLi8v16xZs/SHP/xB0tnT7NLSUq1YsUI/+clPLpqNxWKKRCLJXhIw5F3sydxkG26/gmPov41oNKqcnJwLXp/0I7qnp0d79+5VRUXFf+8kLU0VFRXauXPnObfv7u5WLBZL2AAAw1/SC+jEiRPq6+tTYWFhwuWFhYVqbm4+5/bV1dWKRCL9G6+AA4DLg/kbUVevXq1oNNq/HTlyxHpJAIAUSPrLsPPz85Wenq6WlpaEy1taWlRUVHTO7cPhsMLhcLKXAQAY5JJ+BpSZmamZM2dq27Zt/ZfF43Ft27ZNs2fPTvbdAQCGqAF5I+qqVau0ePFifeMb39CNN96oZ555Rh0dHfrBD34wEHcHABiCBqSA7rrrLn366ad68skn1dzcrK997WvaunXrOS9MAABcvgbkfUBfBe8DgiWfd82PGOH+c1xGRoZzxud9QD734ytVb6Hwee+Q73uo+vr6vHI4K+XvAwIA4MuggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgYkCmYQNDlc/QSp+Mz8Bdn/sZNWqUc0aSPv74Y+dMeXm5c+bTTz91zjQ3Nztn2tvbnTMYeJwBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBMMA0b+B8jRrg/JEKh0ACs5Fy9vb3OmY8++sjrvm6++WbnTF9fn3Pmk08+Scn9BEHgnJH8JpDH43Gv+7occQYEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABMNIkVKpGtzpez8+w0jD4bBzJicnxznz73//2znz0EMPOWck6YMPPnDOfPzxx84Zn/2dlZXlnOnu7nbOSFJXV5dXDl8OZ0AAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBMMIwU3oM709Lcf37xGdzpk4nH484ZSRo5cqRzxmc/+AwWvf76650z//d//+eckaTf/OY3zpl9+/Y5Z5qampwzEydOdM4cO3bMOSP5fW07Ozu97utyxBkQAMAEBQQAMJH0AnrqqacUCoUStilTpiT7bgAAQ9yAPAd0ww036O233/7vnXj80SkAwPA2IM0wYsQIFRUVDcR/DQAYJgbkOaBDhw6ppKREEydO1H333afDhw9f8Lbd3d2KxWIJGwBg+Et6AZWXl2vDhg3aunWrnnvuOTU2NuqWW25RW1vbeW9fXV2tSCTSv5WWliZ7SQCAQSjpBVRZWanvfe97mj59uubPn6+//vWvam1t1auvvnre269evVrRaLR/O3LkSLKXBAAYhAb81QG5ubm67rrrVF9ff97rw+Gw1xsNAQBD24C/D6i9vV0NDQ0qLi4e6LsCAAwhSS+gRx55RLW1tfr444/1j3/8Q3fccYfS09N1zz33JPuuAABDWNJ/BXf06FHdc889OnnypMaOHaubb75Zu3bt0tixY5N9VwCAISwUBEFgvYj/FYvFFIlErJdxWfF9o7DPoMbMzEyv+3LV09PjlfPZF6NHj3bO+EwHaWxsdM4UFBQ4ZyRpz549zpmamhrnzNKlS50zXV1dzhnfY7yhocErh7Oi0ahycnIueD2z4AAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJgY8D9Ih8HPd1Cjz2DR9vZ250xhYaFzxmdAqK+MjAznTGtrq3PGZ0jvBx984JyRpBUrVjhnjh496pzx+QvIc+fOdc74DM6VpM8++8w5E41GnTN9fX3OmeGAMyAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgIlQEASB9SL+VywW85r6Oxz5TvB1lZOT45XzOXTi8bhzZtSoUc4ZX7FYzDnjMw3b52ubnZ3tnPGZuu17X6FQyDlz/fXXO2cOHDjgnPGZUC1JXV1dzhmfr63P42IoiEajF/3+whkQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAEyOsF4ALS9Uw0s7OTq+czzBSn0x6erpzZuTIkc4ZScrPz3fOHD9+3DnjM7jT5+vU3d3tnJGknp4e50w4HHbOjBjh/i3osccec8785S9/cc5IUn19vXPm1KlTzplUPZYGG86AAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmGAY6SCWqmGDZ86c8cr5DJ/0uS+fjM8wTUlqaWlxzkQiEedMPB53zqRy+GROTo5zpre31zmTnZ3tnGloaHDO1NXVOWckv2GuPgNWfR+DQx1nQAAAExQQAMCEcwHt2LFDt912m0pKShQKhbR58+aE64Mg0JNPPqni4mJlZWWpoqJChw4dStZ6AQDDhHMBdXR0aMaMGVq3bt15r1+7dq2effZZPf/889q9e7dGjRql+fPnq6ur6ysvFgAwfDg/W1ZZWanKysrzXhcEgZ555hk9/vjjuv322yVJL7zwggoLC7V582bdfffdX221AIBhI6nPATU2Nqq5uVkVFRX9l0UiEZWXl2vnzp3nzXR3dysWiyVsAIDhL6kF1NzcLEkqLCxMuLywsLD/ui+qrq5WJBLp30pLS5O5JADAIGX+KrjVq1crGo32b0eOHLFeEgAgBZJaQEVFRZLOfTNfS0tL/3VfFA6HlZOTk7ABAIa/pBZQWVmZioqKtG3btv7LYrGYdu/erdmzZyfzrgAAQ5zzq+Da29tVX1/f/3FjY6P279+vvLw8jR8/XitXrtQvfvELXXvttSorK9MTTzyhkpISLVy4MJnrBgAMcc4FtGfPHn3729/u/3jVqlWSpMWLF2vDhg169NFH1dHRoQcffFCtra26+eabtXXrVo0cOTJ5qwYADHmhIJUTDr+EWCzmNdxxOEpLc/8Nqc+QS5/7kaTMzEyvnKsJEyY4Z1pbW73uy2coZG5urnPmxIkTzpnTp087Z3yGfUp+g2Z9BndOnjzZOXPq1CnnjO+3uaNHjzpnfIay+hx3Po/1VItGoxd9Xt/8VXAAgMsTBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMCE859jwOAWCoVSkpH8pv5mZGQ4Z4qLi50zn3zyiXNGkkpLS50zqZrO7DP92GeCtuQ3Tfyqq65yzvzzn/90zowePdo509fX55yR/CZ8+zyehsJk64HAGRAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATDCMdZnyGXPpkfPkMFm1ra3POpKX5/WzV0NDgnBk1apRzJhwOO2c6OjqcM11dXc4ZyX//ufIZEuozMLaurs4548tnSO/lijMgAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJhhGOoj5DAlNT093zmRkZDhnJKm7u9s5M2KE+yHnM4QzLy/POSNJJ06ccM747PNoNOqcCYVCzhmftUl+A1Z9jofCwkLnjM++8xloK6XuMegzlHU44AwIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACYaRpojPIEkfqRyE6DOo8bPPPnPOnDx50jkzdepU54zkty98hqWeOXPGOeNzDGVlZTlnJL/hnT6f09y5c50zDQ0Nzpnc3FznjCSdOnXKOePzuPD52vrcz2DDGRAAwAQFBAAw4VxAO3bs0G233aaSkhKFQiFt3rw54folS5YoFAolbAsWLEjWegEAw4RzAXV0dGjGjBlat27dBW+zYMECNTU19W8vvfTSV1okAGD4cX4RQmVlpSorKy96m3A4rKKiIu9FAQCGvwF5DqimpkYFBQWaPHmyli1bdtFXMXV3dysWiyVsAIDhL+kFtGDBAr3wwgvatm2bfvWrX6m2tlaVlZUXfHlrdXW1IpFI/1ZaWprsJQEABqGkvw/o7rvv7v/3tGnTNH36dE2aNEk1NTXnfc3/6tWrtWrVqv6PY7EYJQQAl4EBfxn2xIkTlZ+fr/r6+vNeHw6HlZOTk7ABAIa/AS+go0eP6uTJkyouLh7ouwIADCHOv4Jrb29POJtpbGzU/v37lZeXp7y8PD399NNatGiRioqK1NDQoEcffVTXXHON5s+fn9SFAwCGNucC2rNnj7797W/3f/z58zeLFy/Wc889pwMHDujPf/6zWltbVVJSonnz5unnP/+5wuFw8lYNABjyQsEgm2gXi8UUiUSsl3FZSUvz+01sPB5P8krOLy8vzzlTUFDgdV/Hjx93zkSjUeeMz/vkfAalNjc3O2ckaeTIkV45V9OmTXPOXOj55IHQ2dnpnOnt7R2AlZwrVY+/ryIajV70eX1mwQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATCT9T3IjeXymVPtMyA2FQs4ZSRoxwv3w8fmcOjo6nDOnTp1yzvje15gxY5wzkyZNcs74fE5tbW3OGcnvmPD52u7Zs8c5k5WV5Zzx5TOB3OcPDAyyP0qQMpwBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMMEw0kEsVYNF09PTnTOS36BGn8zo0aOdM5999plzRpIyMjKcM7FYzDlz6NAh58zp06edMz6fj+T3OYXDYeeMz2BRn+O1q6vLOSP5Ha8+j0GGkQIAkEIUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBMMIw0RQbzgELf+/EZPtnT0+OcGTt2rHOmvb3dOSNJnZ2dzpm8vDznzNGjR50zPkM4Z86c6ZyRpNbWVudMfX29c8bneMjMzHTO+AwVlaS0NPef0X2GCF+uOAMCAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABggmGkKeIz8NNn+KTPIESfgYuS3+eUlZXlnPEZLHr8+HHnjOQ3vDMajTpnfAa5Xnnllc6ZAwcOOGckvwGr1113nXOmqanJOXPy5EnnjM8wYInBogONMyAAgAkKCABgwqmAqqurNWvWLGVnZ6ugoEALFy5UXV1dwm26urpUVVWlMWPGaPTo0Vq0aJFaWlqSumgAwNDnVEC1tbWqqqrSrl279NZbb6m3t1fz5s1TR0dH/20efvhhvfHGG3rttddUW1urY8eO6c4770z6wgEAQ5vTixC2bt2a8PGGDRtUUFCgvXv3as6cOYpGo/rTn/6kjRs36jvf+Y4kaf369br++uu1a9cuffOb30zeygEAQ9pXeg7o81f/fP6Kmb1796q3t1cVFRX9t5kyZYrGjx+vnTt3nvf/6O7uViwWS9gAAMOfdwHF43GtXLlSN910k6ZOnSpJam5uVmZmpnJzcxNuW1hYqObm5vP+P9XV1YpEIv1baWmp75IAAEOIdwFVVVXp4MGDevnll7/SAlavXq1oNNq/HTly5Cv9fwCAocHrjajLly/Xm2++qR07dmjcuHH9lxcVFamnp0etra0JZ0EtLS0qKio67/8VDoe93pQHABjanM6AgiDQ8uXLtWnTJm3fvl1lZWUJ18+cOVMZGRnatm1b/2V1dXU6fPiwZs+enZwVAwCGBaczoKqqKm3cuFFbtmxRdnZ2//M6kUhEWVlZikQiuv/++7Vq1Srl5eUpJydHK1as0OzZs3kFHAAggVMBPffcc5KkW2+9NeHy9evXa8mSJZKk3/3ud0pLS9OiRYvU3d2t+fPn649//GNSFgsAGD5Cgc9EyQEUi8UUiUSslzEo+Awj9flyjhiRupm0qTrcfAesjh071jnT19fnnPGZDuIz7PN/n6N10dra6pz58MMPnTM+g2Z9Btp2dXU5Z6TUHa/DVTQaVU5OzgWvZxYcAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMBE6sYgw5nPlOVQKOSc8Z2G7TMpuKenxzmTn5/vnCkoKHDOSNLIkSOdM6dOnXLOZGRkOGei0ahz5qOPPnLOSLrgXzC+mIkTJzpn/vOf/zhnfCZo+zwuJKZhDzTOgAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJgIBYNs2l4sFlMkErFexqDgM0DRJxOPx50zkpSZmemcycnJSUnG9xgaPXq0c6atrc05c+bMGedMZ2enc8ZnkKsk1dfXO2d8vpX4DFj14fttbpB9exxyotHoRR+/nAEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwMcJ6Abgwn0GIPsNIfYaKSlJvb69z5uTJk86Z1tZW54zPfpCkUaNGOWd8hoReccUVzpmenh7njM++k6T29nbnjO9QW1c+jwuGig5OnAEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwwTDSYcZnIKTPUFHJb8BjWpr7zzxnzpxxzmRkZDhnJKmrq8s547M+nwGmPl/b06dPO2ckacQI928NPutL1QBTDE6cAQEATFBAAAATTgVUXV2tWbNmKTs7WwUFBVq4cKHq6uoSbnPrrbcqFAolbEuXLk3qogEAQ59TAdXW1qqqqkq7du3SW2+9pd7eXs2bN08dHR0Jt3vggQfU1NTUv61duzapiwYADH1OzzRu3bo14eMNGzaooKBAe/fu1Zw5c/ovv+KKK1RUVJScFQIAhqWv9BxQNBqVJOXl5SVc/uKLLyo/P19Tp07V6tWrL/qKn+7ubsVisYQNADD8eb8MOx6Pa+XKlbrppps0derU/svvvfdeTZgwQSUlJTpw4IAee+wx1dXV6fXXXz/v/1NdXa2nn37adxkAgCEqFPi8mUPSsmXL9Le//U3vvvuuxo0bd8Hbbd++XXPnzlV9fb0mTZp0zvXd3d3q7u7u/zgWi6m0tNRnSfAUCoW8cql6H5DPe0V83weUnp7unOnp6XHOpOp9Nn19fc4ZyW99PvfF+4CGt2g0qpycnAte73UGtHz5cr355pvasWPHRctHksrLyyXpggUUDocVDod9lgEAGMKcCigIAq1YsUKbNm1STU2NysrKLpnZv3+/JKm4uNhrgQCA4cmpgKqqqrRx40Zt2bJF2dnZam5uliRFIhFlZWWpoaFBGzdu1He/+12NGTNGBw4c0MMPP6w5c+Zo+vTpA/IJAACGJqfngC70XMH69eu1ZMkSHTlyRN///vd18OBBdXR0qLS0VHfccYcef/zxi/4e8H/FYjFFIpEvuyQkAc8B/RfPAZ3Fc0BIhqQ+B3SpbzilpaWqra11+S8BAJcppmHD60zGl88ZkM/6fH+y9vkp3uesyWd9PvvBZ22S34TvVB5HGB4YRgoAMEEBAQBMUEAAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEw0iRUj5DLn34/hkCH/xJAcAPZ0AAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMDHoCigIAuslAACS4FLfzwddAbW1tVkvAQCQBJf6fh4KBtkpRzwe17Fjx5Sdna1QKJRwXSwWU2lpqY4cOaKcnByjFdpjP5zFfjiL/XAW++GswbAfgiBQW1ubSkpKlJZ24fOcQffnGNLS0jRu3LiL3iYnJ+eyPsA+x344i/1wFvvhLPbDWdb7IRKJXPI2g+5XcACAywMFBAAwMaQKKBwOa82aNQqHw9ZLMcV+OIv9cBb74Sz2w1lDaT8MuhchAAAuD0PqDAgAMHxQQAAAExQQAMAEBQQAMDFkCmjdunW6+uqrNXLkSJWXl+u9996zXlLKPfXUUwqFQgnblClTrJc14Hbs2KHbbrtNJSUlCoVC2rx5c8L1QRDoySefVHFxsbKyslRRUaFDhw7ZLHYAXWo/LFmy5JzjY8GCBTaLHSDV1dWaNWuWsrOzVVBQoIULF6quri7hNl1dXaqqqtKYMWM0evRoLVq0SC0tLUYrHhhfZj/ceuut5xwPS5cuNVrx+Q2JAnrllVe0atUqrVmzRu+//75mzJih+fPn6/jx49ZLS7kbbrhBTU1N/du7775rvaQB19HRoRkzZmjdunXnvX7t2rV69tln9fzzz2v37t0aNWqU5s+fr66urhSvdGBdaj9I0oIFCxKOj5deeimFKxx4tbW1qqqq0q5du/TWW2+pt7dX8+bNU0dHR/9tHn74Yb3xxht67bXXVFtbq2PHjunOO+80XHXyfZn9IEkPPPBAwvGwdu1aoxVfQDAE3HjjjUFVVVX/x319fUFJSUlQXV1tuKrUW7NmTTBjxgzrZZiSFGzatKn/43g8HhQVFQW//vWv+y9rbW0NwuFw8NJLLxmsMDW+uB+CIAgWL14c3H777SbrsXL8+PFAUlBbWxsEwdmvfUZGRvDaa6/13+aDDz4IJAU7d+60WuaA++J+CIIg+Na3vhU89NBDdov6Egb9GVBPT4/27t2rioqK/svS0tJUUVGhnTt3Gq7MxqFDh1RSUqKJEyfqvvvu0+HDh62XZKqxsVHNzc0Jx0ckElF5eflleXzU1NSooKBAkydP1rJly3Ty5EnrJQ2oaDQqScrLy5Mk7d27V729vQnHw5QpUzR+/PhhfTx8cT987sUXX1R+fr6mTp2q1atXq7Oz02J5FzTohpF+0YkTJ9TX16fCwsKEywsLC/Xhhx8arcpGeXm5NmzYoMmTJ6upqUlPP/20brnlFh08eFDZ2dnWyzPR3NwsSec9Pj6/7nKxYMEC3XnnnSorK1NDQ4N++tOfqrKyUjt37lR6err18pIuHo9r5cqVuummmzR16lRJZ4+HzMxM5ebmJtx2OB8P59sPknTvvfdqwoQJKikp0YEDB/TYY4+prq5Or7/+uuFqEw36AsJ/VVZW9v97+vTpKi8v14QJE/Tqq6/q/vvvN1wZBoO77767/9/Tpk3T9OnTNWnSJNXU1Gju3LmGKxsYVVVVOnjw4GXxPOjFXGg/PPjgg/3/njZtmoqLizV37lw1NDRo0qRJqV7meQ36X8Hl5+crPT39nFextLS0qKioyGhVg0Nubq6uu+461dfXWy/FzOfHAMfHuSZOnKj8/PxheXwsX75cb775pt55552EP99SVFSknp4etba2Jtx+uB4PF9oP51NeXi5Jg+p4GPQFlJmZqZkzZ2rbtm39l8XjcW3btk2zZ882XJm99vZ2NTQ0qLi42HopZsrKylRUVJRwfMRiMe3evfuyPz6OHj2qkydPDqvjIwgCLV++XJs2bdL27dtVVlaWcP3MmTOVkZGRcDzU1dXp8OHDw+p4uNR+OJ/9+/dL0uA6HqxfBfFlvPzyy0E4HA42bNgQ/Otf/woefPDBIDc3N2hubrZeWkr96Ec/CmpqaoLGxsbg73//e1BRURHk5+cHx48ft17agGprawv27dsX7Nu3L5AU/Pa3vw327dsXfPLJJ0EQBMEvf/nLIDc3N9iyZUtw4MCB4Pbbbw/KysqC06dPG688uS62H9ra2oJHHnkk2LlzZ9DY2Bi8/fbbwde//vXg2muvDbq6uqyXnjTLli0LIpFIUFNTEzQ1NfVvnZ2d/bdZunRpMH78+GD79u3Bnj17gtmzZwezZ882XHXyXWo/1NfXBz/72c+CPXv2BI2NjcGWLVuCiRMnBnPmzDFeeaIhUUBBEAS///3vg/HjxweZmZnBjTfeGOzatct6SSl31113BcXFxUFmZmZw1VVXBXfddVdQX19vvawB98477wSSztkWL14cBMHZl2I/8cQTQWFhYRAOh4O5c+cGdXV1toseABfbD52dncG8efOCsWPHBhkZGcGECROCBx54YNj9kHa+z19SsH79+v7bnD59OvjhD38YXHnllcEVV1wR3HHHHUFTU5PdogfApfbD4cOHgzlz5gR5eXlBOBwOrrnmmuDHP/5xEI1GbRf+Bfw5BgCAiUH/HBAAYHiigAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABg4v8BsObvABZRCsUAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(np.tile(gradients/(np.max(gradients)), (1,1,3)));"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAecAAAIQCAYAAAC7cqZoAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA0lElEQVR4nO3de3hU1b3G8XcSkkkgNyBECCAkkaLcFYRChSCgoGD1cJSLFkEt6vFWvGurclMBQbFFUUoRlHLESgG1RfEGXhDxhty1gKCggpJIgEACSX7nD09GxgRI9ibMAr+f5+HR7Fm/WWvtPTNv9szsrICZmQAAgDOiIj0AAAAQjnAGAMAxhDMAAI4hnAEAcAzhDACAYwhnAAAcQzgDAOAYwhkAAMcQzgAAOIZwxjE1Y8YMBQIBbd68OdJDOaQhQ4aocePGkR7GL8aIESMUCAQiPYxKa9y4sYYMGRL6efHixQoEAlq8eHHExoQTB+F8glqzZo1+97vfqX79+goGg0pPT9dll12mNWvWRHpoJ4yuXbuqRYsWnmrfe+89jRgxQjt37jy6g6oi33zzjUaMGKFPP/000kPRO++8o379+ql+/fqKjY1VcnKyOnTooFGjRmn79u2RHl6Ve/DBBzV//vxIDwNVjHA+Ac2dO1dnnHGG3njjDV1xxRWaPHmyrrrqKi1atEhnnHGG5s2bF+kh/uK99957Gjly5HEVziNHjox4ON93333q0qWLPv74Yw0ZMkRPPPGEHnzwQTVv3lwPP/ywOnXqFLGxdenSRfv27VOXLl2qtB/C+ZehWqQHgKNr48aNGjRokDIzM/X222+rTp06odv+8Ic/qHPnzho0aJBWrlypzMzMYzau/Px81ahR45j1h8MrKChQbGysoqKOn9/Pn3vuOY0ePVr9+vXTzJkzFRsbG3b7xIkTNXHixMPeh5mpoKBA8fHxR318UVFRiouLO+r3i1+m4+eZiQoZP3689u7dq7/+9a9hwSxJqampmjJlivLz8/XQQw9JkubMmaNAIKC33nqrzH1NmTJFgUBAq1evDm377LPPdPHFF6tWrVqKi4tTu3bt9OKLL4bVlX6u/NZbb+m6665TWlqaGjRocMgxv/DCC+rdu7fS09MVDAaVlZWl0aNHq7i4ONRm+PDhiomJ0ffff1+m/uqrr1ZKSooKCgpC215++WV17txZNWrUUGJionr37l3uW/rz589XixYtFBcXpxYtWvh+VyEQCOiGG24I3W8wGFTz5s31yiuvhNqMGDFCt99+uyQpIyNDgUCgzOfwf//739W2bVvFx8erVq1aGjBggLZs2VKmv8cff1yZmZmKj49X+/bt9c4776hr167q2rVrqE3pZ6GzZ8/WPffco/r166t69eratWuXcnNzddttt6lly5ZKSEhQUlKSzjvvPK1YsSKs/swzz5QkXXHFFaHxzpgxI9Rm2bJl6tWrl5KTk1W9enVlZ2dryZIlZcb77rvv6swzz1RcXJyysrI0ZcqUCu/b++67T6mpqZo2bVqZYJak5ORkjRgxImxb48aN1adPHy1cuFDt2rVTfHx8qM/p06erW7duSktLUzAYVLNmzfTEE0+UuV8z0/33368GDRqoevXqOvvss8t9LB3qM+eK7JvSz903bNigIUOGKCUlRcnJybriiiu0d+/eULtAIKD8/Hw9/fTToeNQ+rn37t27NWzYMDVu3FjBYFBpaWk655xz9Mknn1Rk98I1hhNKenq6NW7c+LBtGjdubA0aNDAzs71791pCQoJdd911ZdqdffbZ1rx589DPq1evtuTkZGvWrJmNGzfOHnvsMevSpYsFAgGbO3duqN306dNNkjVr1syys7Nt0qRJNnbs2LDbNm3aFGp/0UUXWb9+/Wz8+PH2xBNP2CWXXGKS7Lbbbgu1Wb9+vUmySZMmhY2xsLDQatasaVdeeWVo2zPPPGOBQMB69eplkyZNsnHjxlnjxo0tJSUlrN+FCxdaVFSUtWjRwh555BH705/+ZMnJyda8eXNr1KjRYfehmVl2dnbY/jEzk2StW7e2evXq2ejRo+3RRx+1zMxMq169uu3YscPMzFasWGEDBw40STZx4kSbOXOmzZw50/bs2WNmZvfff78FAgHr37+/TZ482UaOHGmpqanWuHFj++GHH0J9TZ482SRZ586d7S9/+YvdcsstVqtWLcvKyrLs7OxQu0WLFoWOR5s2beyRRx6xMWPGWH5+vn344YeWlZVld911l02ZMsVGjRpl9evXt+TkZPv666/NzGzbtm02atQok2RXX311aLwbN240M7M33njDYmNjrWPHjvbwww/bxIkTrVWrVhYbG2vLli0LjWPlypUWHx9vJ598so0ZM8ZGjx5tJ510krVq1cqO9FL0+eefmyT7/e9/f8Tj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Q1lZWRX+W9V9+vTRqFGjdMUVV6hTp05atWqVZs2aVeZzyqysLKWkpOjJJ59UYmKiatSooQ4dOigjI0N/+9vfdN5556l58+a64oorVL9+fX399ddatGiRkpKS9NJLL0mSRo4cqVdeeUWdO3fWddddp6KiotD+PtJHMZJ06aWXavXq1RozZow++OADDRgwQBkZGcrPz9fq1av17LPPKjEx8YifBUvSueeeq9jYWF1wwQW65pprtGfPHk2dOlVpaWlhv3zWqVNHt912m8aMGaM+ffro/PPP1/Lly/Xyyy+HvbNQnqioqArvm8po27atXn/9dT3yyCNKT09XRkaGmjZtqgYNGujiiy9W69atlZCQoNdff10ffvihHn744Ur3AQdE4iviqHorV660gQMHWr169SwmJsbq1q1rAwcOtFWrVh2y5rXXXjNJFggEbMuWLeW22bhxo11++eVWt25di4mJsfr161ufPn1szpw5oTall0t9+OGHZerLu5RqyZIl9utf/9ri4+MtPT3d7rjjDlu4cGGZa0ZLffDBBybJzj333EPOZdGiRdazZ09LTk62uLg4y8rKsiFDhthHH30U1u6f//ynnXbaaRYMBq1Zs2Y2d+5cGzx4sK9Lqcq7nKVRo0ZlLn8ZPXq01a9f36Kiosrsk3/+85921llnWY0aNaxGjRp26qmn2vXXX2+ff/552H385S9/sUaNGlkwGLT27dvbkiVLrG3bttarV6+wfSHJnn/++TLjKigosFtvvdXq1atn8fHx9pvf/MaWLl1q2dnZYZdjmf14OVOzZs2sWrVqZS6rWr58ufXt29dq165twWDQGjVqZP369bM33ngj7D7eeusta9u2rcXGxlpmZqY9+eSTocuIKmrx4sV28cUXhx7bSUlJ1q5dOxs+fLh9++23YW0bNWpkvXv3Lvd+XnzxRWvVqpXFxcVZ48aNbdy4cfbUU0+VORbFxcU2cuTI0D7q2rWrrV69uswxLe8654rum9J98P3334fVlvd8+eyzz6xLly4WHx8fupyrsLDQbr/9dmvdurUlJiZajRo1rHXr1jZ58uQK71e4JWBWifeCAAesWLFCbdq00TPPPKNBgwZFejhOKSkpUZ06ddS3b19NnTo10sMB4BGfOeO4M3XqVCUkJKhv376RHkpEFRQUlHn7/5lnnlFubm7Yn+8EcPzhM2ccN156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",
      "text/plain": [
       "<Figure size 600x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "integ_grads = IntegratedGradients(model)\n",
    "attributed_ig, delta = integ_grads.attribute(captum_input, target=sample_targets[0].item(), baselines=captum_input * 0, \n",
    "                              return_convergence_delta=True)\n",
    "attributed_ig = np.reshape(attributed_ig.squeeze().cpu().detach().numpy(), (28, 28, 1))\n",
    "_ = viz.visualize_image_attr(attributed_ig, orig_image, method=\"blended_heat_map\",sign=\"all\", show_colorbar=True, \n",
    "                             title=\"Overlayed Integrated Gradients\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/conda/lib/python3.10/site-packages/captum/attr/_core/deep_lift.py:336: UserWarning: Setting forward, backward hooks and attributes on non-linear\n",
      "               activations. The hooks and attributes will be removed\n",
      "            after the attribution is finished\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "data": {
      "image/png": "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WD8jR45UdHT0D447Pj4+bA75+fnq0aOHiouLtW3bttBlw4YN07p167Rjx47QsZdeekktW7ZUZmamJOmdd97RoUOHlJ2dHRpjfn6+oqOj1bVrV61cuVKStGfPHm3YsEHDhw9XUlJS6Pp+9KMfVdvrqwkJCaE5Sd+9Ua+srEyDBg0KG1tqaqrS09NDY9uwYYO2b9+u2267TQcOHAi1O3LkiHr16qUPPvig3Ju27r333rDv77//fknSsmXLqmUuwLmAN4TBpGDoBsPgTE4P8eDrmosWLVKvXr0kffeUdkZGhi6++GJJUm5urpxzGj9+vMaPH1/h9e7fv1/NmzcPfd+mTZtKjXvLli361a9+pffeey/0C0PQqa/XDh48WGPGjNFLL72kxx57TAUFBfqf//kfPfjggwoEApKk7du3S5Kuv/76CvtKTEyUJH355ZeSpPT09HJt2rdvr88++6xSYz+boqIiSd/fztu3b5dzrsI+pe/fjBWcw/Dhw8943QUFBWrYsGHo+9OvMy0tTVFRUbwOjH8qhDNMSkpKUtOmTbVp06azttu0aZOaN28eCqrY2NjQ68bPP/+89u3bpzVr1uipp54K1QTP1B5++GH16dOnwutt165d2PennhGfyaFDh5SZmanExERNmjRJaWlpiouL02effaZHHnkk7AyxYcOG6t+/fyicFy9erOPHj4e9WzrYfv78+UpNTS3XX506tXf3Db6RLni7lJWVKRAIaPny5RU+oxA80w7OYfr06crIyKjwuoNtzyT4ywrwz4Rwhln9+/fX7NmztXr1anXv3r3c5X/729+0c+dO3X333WHHBw8erBdffFHvvvuutm7dKudc6CltSaGPXcXExKh3797VNt5Vq1bpwIEDWrJkiXr27Bk6npeXV2H7YcOGacCAAfr444/10ksvqXPnzurQoUPo8rS0NElSkyZNzjrOVq1aSfr+LPVUX3zxhae5nKq0tFQvv/yy6tWrF1qHtLQ0OefUpk2b0DMSFQnOITExsdK39fbt28OeqcjNzVVZWVmN/aUzwh8W8ZozzBo7dqzi4+N1991368CBA2GXHTx4UD/96U9Vr1690Edhgnr37q1GjRpp0aJFWrRokbp06RL2YN+kSRNdd911mjVrlvbs2VOu34o+4lQZwTNI51zo2IkTJ/T8889X2L5fv35KSUnRtGnT9P7775f7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EQvnQCCgoqIi7dq1S4mJiZEaRrU7fPiwWrZsybzOEefjvM7HOUnM61xzvs8rcPqzY9Us4k9rJyYmnlcLF8S8zi3n47zOxzlJzOtcc77Oq6bxhjAAAIwhnAEAMCZi4RwbG6sJEyYoNjY2UkOoEczr3HI+zut8nJPEvM41zMufgKvpt5wBAIAq4WltAACMIZwBADCGcAYAwBjCGQAAY2osnJ988kl169ZN9erVU3JycqVqnHN67LHH1LRpU8XHx6t3797avn17WJuDBw/q9ttvV2JiopKTk3XXXXepqKioBmZQsar2v3PnTgUCgQq//vSnP4XaVXT5woULa2NKkrzdrtddd125Mf/0pz8Na/PVV18pKytL9erVU5MmTTR27FiVlJTU5FTCVHVeBw8e1P3336/27dsrPj5eF110kUaPHq2CgoKwdrW9XjNnzlTr1q0VFxenrl276qOPPjpr+z/96U+65JJLFBcXp06dOmnZsmVhl1fmvlYbqjKv2bNnq0ePHmrYsKEaNmyo3r17l2s/YsSIcuvSt2/fmp5GOVWZ17x588qNOS4uLqyNhfWqypwqemwIBALKysoKtbGwVh988IF+/OMfq1mzZgoEAnrttdd+sGbVqlW68sorFRsbq3bt2mnevHnl2lT1/lohV0Mee+wx9/TTT7uHHnrIJSUlVapm6tSpLikpyb322mtu48aN7qabbnJt2rRxR48eDbXp27evu+KKK9yHH37o/va3v7l27dq57OzsGppFeVXtv6SkxO3Zsyfsa+LEiS4hIcEVFhaG2klyc+fODWt36rxrmpfbNTMz040cOTJszAUFBaHLS0pKXMeOHV3v3r3d+vXr3bJly1xKSop79NFHa3o6IVWd1+bNm93AgQPdG2+84XJzc927777r0tPT3S233BLWrjbXa+HCha5u3bruhRdecFu2bHEjR450ycnJbt++fRW2X7NmjYuOjna//vWvXU5OjvvVr37lYmJi3ObNm0NtKnNfq2lVnddtt93mZs6c6davX++2bt3qRowY4ZKSktzu3btDbYYPH+769u0bti4HDx6srSk556o+r7lz57rExMSwMe/duzesTaTXq6pzOnDgQNh8Pv/8cxcdHe3mzp0bamNhrZYtW+Z++ctfuiVLljhJbunSpWdt/7//+7+uXr167qGHHnI5OTnu2WefddHR0e4vf/lLqE1Vb6szqbFwDpo7d26lwrmsrMylpqa66dOnh44dOnTIxcbGuldeecU551xOTo6T5D7++ONQm+XLl7tAIOC+/vrrah/76aqr/4yMDPeTn/wk7FhlfjBqitd5ZWZmugceeOCMly9btsxFRUWFPdD87ne/c4mJie748ePVMvazqa71evXVV13dunXdyZMnQ8dqc726dOni7r333tD3paWlrlmzZm7KlCkVth80aJDLysoKO9a1a1d39913O+cqd1+rDVWd1+lKSkpcgwYN3Isvvhg6Nnz4cDdgwIDqHmqVVHVeP/QYaWG9/K7VM8884xo0aOCKiopCxyys1akqc5/+xS9+4Tp06BB2bPDgwa5Pnz6h7/3eVkFmXnPOy8vT3r171bt379CxpKQkde3aVWvXrpUkrV27VsnJybr66qtDbXr37q2oqCitW7euxsdYHf1/+umn2rBhg+66665yl917771KSUlRly5d9MILL9T4ridBfub10ksvKSUlRR07dtSjjz6q4uLisOvt1KmTLrzwwtCxPn366PDhw9qyZUv1T+Q01fXzUlBQoMTERNWpE/6n6GtjvU6cOKFPP/007H4RFRWl3r17h+4Xp1u7dm1Ye+m72z3YvjL3tZrmZV6nKy4u1smTJ9WoUaOw46tWrVKTJk3Uvn17/exnP9OBAweqdexn43VeRUVFatWqlVq2bKkBAwaE3T8ivV7VsVZz5szRkCFDVL9+/bDjkVwrL37ovlUdt1VQxDe+CNq7d68khT2QB78PXrZ37141adIk7PI6deqoUaNGoTY1PUa//c+ZM0eXXnqpunXrFnZ80qRJuv7661WvXj2tWLFC99xzj4qKijR69OhqG/+ZeJ3XbbfdplatWqlZs2batGmTHnnkEX3xxRdasmRJ6HorWs/gZTWtOtYrPz9fkydP1qhRo8KO19Z65efnq7S0tMLbcdu2bRXWnOl2P/V+FDx2pjY1zcu8TvfII4+oWbNmYQ+Effv21cCBA9WmTRvt2LFD//Ef/6F+/fpp7dq1io6OrtY5VMTLvNq3b68XXnhBl19+uQoKCjRjxgx169ZNW7ZsUYsWLSK+Xn7X6qOPPtLnn3+uOXPmhB2P9Fp5cab71uHDh3X06FH94x//8P1zHVSlcB43bpymTZt21jZbt27VJZdcUqVBRFpl5+XX0aNH9fLLL2v8+PHlLjv1WOfOnXXkyBFNnz7d14N9Tc/r1MDq1KmTmjZtql69emnHjh1KS0vzfL0/pLbW6/Dhw8rKytJll12mxx9/POyymlgvVN7UqVO1cOFCrVq1KuzNU0OGDAn9v1OnTrr88suVlpamVatWqVevXpEY6g+69tprde2114a+79atmy699FLNmjVLkydPjuDIqsecOXPUqVMndenSJez4ubhWtalK4fzzn/9cI0aMOGubtm3behpIamqqJGnfvn1q2rRp6Pi+ffuUkZERarN///6wupKSEh08eDBU70Vl5+W3/8WLF6u4uFjDhg37wbZdu3bV5MmTdfz4cc9/w7W25hXUtWtXSVJubq7S0tKUmppa7l2K+/btkyTz61VYWKi+ffuqQYMGWrp0qWJiYs7avjrWqyIpKSmKjo4O3W5B+/btO+McUlNTz9q+Mve1muZlXkEzZszQ1KlT9de//lWXX375Wdu2bdtWKSkpys3NrZUHfD/zCoqJiVHnzp2Vm5srKfLr5WdOR44c0cKFCzVp0qQf7Ke218qLM923EhMTFR8fr+joaN/rH1KlV6g9qOobwmbMmBE6VlBQUOEbwj755JNQm7fffrvW3xDmtf/MzMxy7/o9kyeeeMI1bNjQ81irorpu19WrVztJbuPGjc65798Qduq7FGfNmuUSExPdsWPHqm8CZ+B1XgUFBe6aa65xmZmZ7siRI5XqqybXq0uXLu6+++4LfV9aWuqaN29+1jeE9e/fP+zYtddeW+4NYWe7r9WGqs7LOeemTZvmEhMT3dq1ayvVx65du1wgEHCvv/667/FWlpd5naqkpMS1b9/ePfjgg845G+vldU5z5851sbGxLj8//wf7iMRanUqVfENYx44dw45lZ2eXe0OYn/UPjadKravgyy+/dOvXrw99bGj9+vVu/fr1YR8fat++vVuyZEno+6lTp7rk5GT3+uuvu02bNrkBAwZU+FGqzp07u3Xr1rnVq1e79PT0Wv8o1dn63717t2vfvr1bt25dWN327dtdIBBwy5cvL3edb7zxhps9e7bbvHmz2759u3v++eddvXr13GOPPVbj8wmq6rxyc3PdpEmT3CeffOLy8vLc66+/7tq2bet69uwZqgl+lOqGG25wGzZscH/5y19c48aNa/2jVFWZV0FBgevatavr1KmTy83NDfuYR0lJiXOu9tdr4cKFLjY21s2bN8/l5OS4UaNGueTk5NC74IcOHerGjRsXar9mzRpXp04dN2PGDLd161Y3YcKECj9K9UP3tZpW1XlNnTrV1a1b1y1evDhsXYKPKYWFhe7hhx92a9eudXl5ee6vf/2ru/LKK116enqt/DLodV4TJ050b7/9ttuxY4f79NNP3ZAhQ1xcXJzbsmVL2NwjuV5VnVNQ9+7d3eDBg8sdt7JWhYWFoWyS5J5++mm3fv169+WXXzrnnBs3bpwbOnRoqH3wo1Rjx451W7dudTNnzqzwo1Rnu60qq8bCefjw4U5Sua+VK1d+3/n/fVY0qKyszI0fP95deOGFLjY21vXq1ct98cUXYdd74MABl52d7RISElxiYqK78847wwK/pv1Q/3l5eeXm6Zxzjz76qGvZsqUrLS0td53Lly93GRkZLiEhwdWvX99dccUV7ve//32FbWtKVef11VdfuZ49e7pGjRq52NhY165dOzd27Niwzzk759zOnTtdv379XHx8vEtJSXE///nPwz6SZG1eK1eurPDnVpLLy8tzzkVmvZ599ll30UUXubp167ouXbq4Dz/8MHRZZmamGz58eFj7V1991V188cWubt26rkOHDu6tt94Ku7wy97XaUJV5tWrVqsJ1mTBhgnPOueLiYnfDDTe4xo0bu5iYGNeqVSs3cuTIKj8oVoeqzGvMmDGhthdeeKG78cYb3WeffRZ2fRbWq6o/g9u2bXOS3IoVK8pdl5W1OtP9PTiX4cOHu8zMzHI1GRkZrm7duq5t27ZhGRZ0ttuqstgyEgAAY8x8zhkAAHyHcAYAwBjCGQAAYwhnAACMIZwBADCGcAYAwBjCGQAAYwhnAACMIZwBADCGcAYAwBjCGQAAYwhnAACM+f+Mmp8V29GtIAAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 600x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "deep_lift = DeepLift(model)\n",
    "attributed_dl = deep_lift.attribute(captum_input, target=sample_targets[0].item(), baselines=captum_input * 0, \n",
    "                              return_convergence_delta=False)\n",
    "attributed_dl = np.reshape(attributed_dl.squeeze(0).cpu().detach().numpy(), (28, 28, 1))\n",
    "_ = viz.visualize_image_attr(attributed_dl, orig_image, method=\"blended_heat_map\",sign=\"all\",show_colorbar=True, \n",
    "                          title=\"Overlayed DeepLift\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (Local)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
